0x01 Sign
签到题
载入ida
Alt+T查找RCTF即得flag
0x02 git
签到题
查看commit信息:
Revert
# 请为您的变更输入提交说明。以 '#' 开始的行将被忽略,而一个空的提交
# 说明将会终止提交。
#
# 位于分支 rctf
# 要提交的变更:
# 删除: flag.txt
#
需要利用git revert来恢复flag.txt
git bash 下打开:
git reflog
看到有一次合并:
f671986 HEAD@{5}: checkout: moving from master to develop
而后:
git revert f671986
即可恢复txt文件,得到flag
0x03 cpushop
hash长度扩展攻击
我们需要flag的价格:price<money
利用hashdump附加请求信息:&price=0
而后根据正常的sign值得到附加信息后的sign
发送新的请求即得flag
0x04 Number Game
第一关直接碰撞即可
而后可以看到number game是很早的一个猜数游戏
github上可以找到一种生成树策略:
https://github.com/AustinGuo/GessNumber
直接套入脚本,过关即得flag
0x05 babyre
调试后发现堆中几个参数不可控
直接运行发现每个字节依次运算,与位置无关
找到对应关系根据密文破解
或者直接pwntools按位爆破也可以:
key = [0xb8a6ee10,0xb986234f,0xf1b1602,0x2571a420,0x805feee3,0x958b0534,0x8a0ad7,0xf3a32248,0x45c66c5a,0xcda47499,0xee152dad,0x77591917,0xb118982f,0x7386bd6a,0xdf1708d2,0x67d38af2,0xc567b6b6,0x526ba076,0xae4c822d,0xa1e10430,0xc3f2de73,0x7f08e077,0x7240b7ba,0x20067e4b,0x28def57e,0x545c15ad,0xb02881cf,0x15d71041,0x9f9e33a3,0x6958d9df,0x51a1924f,0x299fa574,0x3e968078,0x6e7b9de9,0x3e5daef6,0x70573efe,0x94bec810,0xde26ea93,0x7f7a8193,0x7147adb7,0xe554cf78,0xf0dc5e15,0x730a451b,0x90347c6c,0x8699b5f,0x834c762a,0x97e8bb26,0xc1ca6398,0x6aed0d44,0xe498e228,0xb80c91fe,0x9935e5ee,0xbeed92ae,0x5067d2a7,0x239b768c,0x3b6eb4ce,0x354689e2,0x8028bcb,0x86447eef,0x86c95e28,0x8a0ad7,0xe887091c,0xa8f27e12,0x7d8aa463,0xc15dfd82,0x9c513266,0x30a3769a,0xaa8afbba,0x1edc3864,0xaa7a15df,0x6c1194bf,0xeade7bf1,0x115f3801,0x42bafa35,0xa5a30516,0x4e032f9f,0x121ee8ab,0xe75d55e4,0x7f543d62,0x153f1a32,0x6d076b18,0xf3857621,0x6d7df3e1,0xfbcb7aa0,0x36b897bd,0x82c974fc,0xf5650025,0x90f77ba1,0xf9b8d92b,0x9323bc07,0xa5c88e2,0x7390c17b,0x760e65f9,0xb13ad888,0x1667aba8]
crypto = [0xb80c91fe,0x70573efe,0xbeed92ae,0x7f7a8193,0x7390c17b,0x90347c6c,0xaa7a15df,0xaa7a15df,0x526ba076,0x153f1a32,0x545c15ad,0x7d8aa463,0x526ba076,0xfbcb7aa0,0x7d8aa463,0x9c513266,0x526ba076,0x6d7df3e1,0xaa7a15df,0x9c513266,0x1edc3864,0x9323bc07,0x7d8aa463,0xfbcb7aa0,0x153f1a32,0x526ba076,0xf5650025,0xaa7a15df,0x1edc3864,0xb13ad888]
flag=""
for i in crypto:
j=0
for k in range(32,127):
if key[k]==i:
flag+=chr(k)
break
k+=1
print flag
0x06 babyre2
载入ida调试,看到这里:
mov rax, 20656D6F636C6557h
mov qword ptr [rsp+198h+s], rax
mov rax, 2046544352206F74h
mov [rsp+198h+var_D0], 0FFFFFFFFFFFFFFFFh
mov [rsp+198h+var_110], rax
mov rax, 6548202138313032h
mov [rsp+198h+var_C8], 0FFFFFFFFFFFFFFFFh
mov [rsp+198h+var_108], rax
mov rax, 2061207369206572h
mov [rsp+198h+var_C0], 0FFFFFFFFFFFFFFFFh
mov [rsp+198h+var_100], rax
mov rax, 6320455279626142h
mov [rsp+198h+var_B8], 0FFFFFFFFFFFFFFFFh
mov [rsp+198h+var_B0], 0FFFFFFFFFFFFFFFFh
mov [rsp+198h+var_A8], 0FFFFFFFFFFFFFFFFh
mov [rsp+198h+var_A0], 0FFFFFFFFFFFFFFFFh
mov [rsp+198h+var_F8], rax
mov rax, 65676E656C6C6168h
mov [rsp+198h+var_F0], rax
mov rax, 756F7920726F6620h
mov [rsp+198h+var_E8], rax
这些数据依照顺序依次参与:
mov rax, qword ptr [rsp+198h+s]
xor ecx, ecx
mul [rsp+198h+var_198]
mov rsi, rdx
mov rdi, rax
mov rdx, 0FFFFFFFFFFFFFFC5h
call sub_400BA0
这里可以看到几个参数:
我们输入字符与上文数据的乘积
乘积高16位存于rsi寄存器
乘积低16位存于rdi寄存器
参数0FFFFFFFFFFFFFFC5h存于rdx中
看一下sub_400BA0的伪代码:
很显然进行运算的只有:
else
{
if ( a2 <= *((_QWORD *)&a1 + 1) )
{
if ( !a2 )
v3 = 1 / 0uLL;
*(_QWORD *)&v17 = a1;
*((_QWORD *)&v17 + 1) = *((_QWORD *)&a1 + 1) % v3;
v5 = v17 % v3;
}
else
{
v5 = a1 % a2;
}
result = v5;
}
return result;
很显然,这里的高16位与低16位都需要对0FFFFFFFFFFFFFFC5h取模,而后return
继续看数次调用sub_400BA0并retn后的运算:
movdqa xmm1, [rsp+198h+var_98]
mov qword ptr [rsp+198h+var_28+8], rax
movdqa xmm0, cs:xmmword_602070
pxor xmm1, cs:xmmword_602060
movdqa xmm4, [rsp+198h+var_78]
pxor xmm0, [rsp+198h+var_88]
movdqa xmm3, [rsp+198h+var_68]
pxor xmm4, cs:xmmword_602080
movdqa xmm2, [rsp+198h+var_58]
pxor xmm3, cs:xmmword_602090
por xmm1, xmm0
pxor xmm2, cs:xmmword_6020A0
movdqa xmm0, [rsp+198h+var_38]
por xmm4, xmm1
movdqa xmm1, [rsp+198h+var_48]
pxor xmm0, cs:xmmword_6020C0
por xmm3, xmm4
pxor xmm1, cs:xmmword_6020B0
por xmm2, xmm3
movdqa xmm3, xmm2
movdqa xmm2, xmm1
movdqa xmm1, xmm0
movdqa xmm0, cs:xmmword_6020D0
por xmm2, xmm3
pxor xmm0, xmmword ptr [rsp+198h+var_28]
por xmm1, xmm2
por xmm0, xmm1
movdqa xmm1, xmm0
psrldq xmm1, 8
por xmm0, xmm1
movq rax, xmm0
test rax, rax
jz short loc_400A86
jz short loc_400A86
mov edi, offset s ; "Incorrect."
call _puts
loc_400A68: ; CODE XREF: main+520↓j
xor eax, eax
mov rcx, [rsp+198h+var_10]
xor rcx, fs:28h
jnz short loc_400A92
add rsp, 190h
pop rbp
loc_400A86: ; CODE XREF: main+4EC↑j
mov edi, offset aCorrectCongrat ; "Correct. Congratulations!"
call _puts
jmp short loc_400A68
对应伪代码(实际汇编的运算逻辑更清晰一些):
5 = _mm_or_si128(
_mm_xor_si128(_mm_load_si128((const __m128i *)&xmmword_6020D0), v46),
_mm_or_si128(
_mm_xor_si128(_mm_load_si128((const __m128i *)&v45), (__m128i)xmmword_6020C0),
_mm_or_si128(
_mm_xor_si128(_mm_load_si128((const __m128i *)&v44), (__m128i)xmmword_6020B0),
_mm_or_si128(
_mm_xor_si128(_mm_load_si128((const __m128i *)&v43), (__m128i)xmmword_6020A0),
_mm_or_si128(
_mm_xor_si128(_mm_load_si128((const __m128i *)&v42), (__m128i)xmmword_602090),
_mm_or_si128(
_mm_xor_si128(_mm_load_si128((const __m128i *)&v41), (__m128i)xmmword_602080),
_mm_or_si128(
_mm_xor_si128(v4, (__m128i)xmmword_602060),
_mm_xor_si128(_mm_load_si128((const __m128i *)&xmmword_602070), v40))))))));
if ( (unsigned __int64)*(_OWORD *)&_mm_or_si128(v5, _mm_srli_si128(v5, 8)) )
puts("Incorrect.");
else
puts("Correct. Congratulations!");
return 0LL;
很显然,这里只是对应比较运算后的数据与内存中固定的数据:
.data:0000000000602060 xmmword_602060 xmmword 7BA58F82BD8980352B7192452905E8FBh
.data:0000000000602060 ; DATA XREF: main+438↑r
.data:0000000000602070 xmmword_602070 xmmword 163F756FCC221AB0A3112746582E1434h
.data:0000000000602070 ; DATA XREF: main+430↑r
.data:0000000000602080 xmmword_602080 xmmword 0DCDD8B49EA5D7E14ECC78E6FB9CBA1FEh
.data:0000000000602080 ; DATA XREF: main+45B↑r
.data:0000000000602090 xmmword_602090 xmmword 0AAAAAAAAAA975D1CA2845FE0B3096F8Eh
.data:0000000000602090 ; DATA XREF: main+46C↑r
.data:00000000006020A0 xmmword_6020A0 xmmword 55555555555559A355555555555559A3h
.data:00000000006020A0 ; DATA XREF: main+478↑r
.data:00000000006020B0 xmmword_6020B0 xmmword 55555555555559A355555555555559A3h
.data:00000000006020B0 ; DATA XREF: main+4A2↑r
.data:00000000006020C0 xmmword_6020C0 xmmword 55555555555559A355555555555559A3h
.data:00000000006020C0 ; DATA XREF: main+496↑r
.data:00000000006020D0 xmmword_6020D0 xmmword 55555555555559A355555555555559A3h
.data:00000000006020D0 ; DATA XREF: main+4BA↑r
shift+E提取数据
我们需要求出对应的x满足:
x:所要求的的flag
y:内存中的比较数据(已知)
k:最开始的参与乘积的数据(已知)
x需要满足:
kx ≡ y mod 0FFFFFFFFFFFFFFC5h
实际上,我们只需要求k关于0FFFFFFFFFFFFFFC5h的乘法逆元,即X满足:
kX ≡ 1 mod 0FFFFFFFFFFFFFFC5h
而后kXy即满足:
kXy ≡ y mod 0FFFFFFFFFFFFFFC5h
故而:
所求:x=Xy
这里直接利用PyCrypto库中的inverse函数(求乘法逆元)即可:
逐位运算即得flag:
from pwn import *
from Crypto.Util.number import *
key1 =[0x20656D6F636C6557,0x2046544352206F74,0x6548202138313032,0x2061207369206572,0x6320455279626142,0x65676E656C6C6168,0x756F7920726F6620,0xFFFFFFFFFFFF002E,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF]
key2 =[0x2B7192452905E8FB,0x7BA58F82BD898035,0xA3112746582E1434,0x163F756FCC221AB0,0xECC78E6FB9CBA1FE,0x0DCDD8B49EA5D7E14,0xA2845FE0B3096F8E,0x0AAAAAAAAAA975D1C,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3,0x55555555555559A3]
key3 = 0xFFFFFFFFFFFFFFC5
flag=""
for i in range(len(key1)):
flag+=p64(key2[i] * inverse(key1[i],key3)%key3)
print flag
网友评论