强网杯出土记

经过上次的失败经历后,我相信即将到来的强网杯青少年赛会阳间许多,而事实却并不是这样。

以下按做题顺序写wp(这次就我一个人做出来题可还行):

1. 签到

打开exe可以直接看到flag(很开心拿到一血

flag{鲸鱼带你进入鲸奇世界}

2. Lihua’s for

第一步查壳:

第二步打开64位ida,定位到主函数

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char flag[42]; // [rsp+20h] [rbp-60h] BYREF
int a[42]; // [rsp+50h] [rbp-30h] BYREF
int b[42]; // [rsp+100h] [rbp+80h]
int i_0; // [rsp+1B4h] [rbp+134h]
int i; // [rsp+1B8h] [rbp+138h]
int good; // [rsp+1BCh] [rbp+13Ch]

_main();
qmemcpy(a, &unk_403040, sizeof(a));
puts("input flag");
scanf("%s", flag);
puts(flag);
for ( i = 0; i <= 41; ++i )
b[i] = i ^ flag[i];
for ( i_0 = 0; i_0 <= 41; ++i_0 )
{
if ( a[i_0] != b[i_0] )
{
good = 0;
break;
}
good = 1;
}
if ( good == 1 )
printf("good~");
else
printf("error!");
return 0;
}

可以发现程序的原理是将用户输入的flag[i]跟i异或后与a[i]比较。

第三步直接把a[i]的值dump出来,编写exp即可解出flag。

(又水了一道reverse签到题)

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
#include <bits/stdc++.h>
using namespace std;

int n,m;
int a[] =
{
0x66, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00, 0x63, 0x00,
0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00,
0x64, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x36, 0x00,
0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x39, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00,
0x3A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00,
0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x22, 0x00,
0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7A, 0x00,
0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,
0x29, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x16, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
0x45, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x47, 0x00,
0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
int main()
{
for(int i=0;i<42;i++)
{
for(int t=1;t<255;t++)
{
if((i^t)==a[i*4])
{cout<<char(t);break;}
}
}
return 0;
}

flag{a41be465-a50f-4124-b7ba-2766aff6baf2}

3. Crypto2

给定:

1
2
3
4
5
n1=20663949646446787716947370247427064802032290773674573417491154934657966734874241036307633567695175131014840617208051931753476223149652427133485160771068994073566431652969243962290116898345337189704974833817335135391974497754670322430159624252007005736522065638860351992074099453212550475552692645688800084354832716662142860413158369020005830095049988807931794736876563293916525328174812726514626029103506607813186690909585870115364600969148482617083817273910020722354923244093624032174432568413187131385994452769295894606345768596899824635672699945050103814681553981019917552667794514804359500108947102234376726009329
n2=23260834024376640092536888922041147168387702014814910549469730354688848760379274203088716649609675449936234732528778557041701524981200368996310064584479657042098426164366286670115392015865853892816983885530312074073396422301009513106258655315791720535737587913264728919869055970993613641008348186263870234072422880033882864603438907070864271470483691729705421547143623305055532339107777314310976947392833395180922324243244784018964736826235018388498516438612962123562977736924674510730898077787055367234786519915374446506561992135856904927351307275140543635152771670410211235702283822782412971646092584646758107766061
c1=20522772249591436865905796103232542494211695376973377722875606678999899690405480809231671346489821878050354380591999935960795888483664473952207298504196203830543208477229162177648586683957831016664569242538775928728009699300145355818417233892295367828930893733774091897666206696635744262884229680137381841581000794056156842812583057103472764486608022028638288161256424936523444974815727764620634174112474612238992061186937613171878635903455700636894570504376153482600057655480654731180740098435209814585459376319844315388048636156465832997913885636776523217188604040216732137108997444787157007665652718553013424347649
c2=18715009944766815149492560645051626329204114049927707292306481018724323433701970253541495090244787378826569549885480491764057526828531429033378143426272248940256432423939977805246742287886281853484696625486522535042794403288199393432900065504766428665320682811338887618389589263597065738414638013423594446322359052784842619755053094028050245325637698678444632860097510081832077842610716042473697478416213915805481704537884611126069907812621750817901278803326304784057145916721693930579344441283586458621033705530309835431139751025999089707480829034535026967779441379062426254038310930863215188888662357133997908688736
e=65537

经检验得n1,n2不互质,可以参考 https://zhuanlan.zhihu.com/p/76228394 中的方法进行解密。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import gmpy2  
from Crypto.Util.number import long_to_bytes
c1 = ...
c2 = ...
n1 = ...
n2 = ...
e = 65537
p12 = gmpy2.gcd(n1, n2)
assert (p12 != 1)
q1 = n1 / p12
q2 = n2 / p12
d1 = gmpy2.invert(e, (p12 - 1) * (q1 - 1))
d2 = gmpy2.invert(e, (p12 - 1) * (q2 - 1))
m1 = pow(c1, d1, n1)
m2 = pow(c2, d2, n2)
print long_to_bytes(m1)+long_to_bytes(m2)

flag{afb1e6f2-9acb-efde-ad7c-246a99d8f1fd}

4. 拼图

或许可以写脚本做这道题,但是我不会,只能肉眼观察与众不同的图片,拼接成这样一幅图: (使用了PowerPoint编辑的)

做到这儿我就不大会了,然而此时名次大概在30+,离线下还差几名。而且我恰好卡在一个看上去马上要做出来的misc题上:

于是我找到了那位安徽的同学(见超短裙子回忆录的第十二章,经过了一个暑假的磨练,他变强了许多),打算跟他做py交易。我把那道reverse的解法给他,他就给我了这道题的wp。

提交了flag{Hamsters_are_so_cute}发现答案不正确。

考虑到cute右边没有立即跟上右括号,说明cute的右边可能含有一些标点来占位。

容易忽略的标点符号有“!“和”|“,因为它会与大括号相混导致误判。

通过对cute后面加1~5个“!“与”|“,成功试出来了正确的flag

flag{Hamsters_are_so_cute!!!}

这™谁想得到啊!!!

5. Crypto1

眼看离比赛结束就只有20分钟了,虽然此时的我rk22,但按照上次比赛的惯例,最后的名次肯定飞速下降,必须要再AC一道题才能稳住线下赛的资格。

于是我们有:

1
2
3
4
5
n=96722669749951212913756678234358651184134068407812470434435916603156818917545841439779031943800634250032106764154804309935557678512858630048212204696471487762160744924838010746445510979202735123140536599975731157563069594497905809587369126155476201977830809090473053692189364335223367147692962090288185113654598050169422517553085833257142179937154768657039042632343562454149914801329414293361879935460883633117988279426277638667508115319494914342600199690237441851088350726869553691992122821267990343643644523989413546160765907845604067031798179773495433134648132709349683621175243064236059479837244518879574919017301667066698329442453248971033564328161407342561250703168154214939772631586519304164853651
c1=66738113223447221430009739914948303261002811553064307532926788024694319846909340806982708347904688420671656410554852340732395818007063648478593071665936277836988050526188064146099581039172667768507259894363266310279948729552649788129953872816024709989260060633285022337107662251504618369065597018450927041881262189584381809106166042131798086882746986243210896131714227544235843922107304728228549916171484199199612243776469423359120753888158616202476325705252715374109256790899923317253605743212561589807498078080069511918514647943399566630574192829185904868376879831247378819590121286186417825591746918495311372015707767009078229770450338244309693800180936418605756818618708750868807720566288044943952844
c2=88330949146651042517337653740810385187361689012501792799900873279978736035790659211001047937337215121948527017022967642906632732136313750277237761910710915459733551421653259986088596828049455592613225962133163865584111828012197112528645520371075411167515961263199635568730334149461654340122507778194391601956023625429418297129608911450200836427221311442323768087256798964844787274408624548839536279704401007441198390922847003287643673183230633728790263593607595427088882078742699027563601046309308221108391158848644822374865676056755011459026909057983805069264236657111115914570543103494726584296335044897998794251877515750910330960179539465060133592380802344398038815679281272098815068185059127533110716
e1=49
e2=35

很明显是共模攻击的模型,但是e1与e2并不互质,最大公约数为7。

这里需要将e1与e2同时/7,从而m变为了

这时就可以使用低加密指数攻击了,题目代码如下:

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
# py2 sameNAttack.py
import primefac
from Crypto.Util.number import long_to_bytes
n=...
e1=...
e2=...
c1=...
c2=...
def same_n_attack(n,e1,e2,c1,c2):
def egcd(a,b):
x, lastX = 0, 1
y, lastY = 1, 0
while (b != 0):
q = a // b
a, b = b, a % b
x, lastX = lastX - q * x, x
y, lastY = lastY - q * y, y
return (lastX, lastY)
s = egcd(e1,e2)
s1 = s[0]
s2 = s[1]
if s1 < 0:
s1 = -s1
c1 = primefac.modinv(c1, n)
if c1 < 0:
c1 += n
elif s2 < 0:
s2 = -s2
c2 = primefac.modinv(c2, n)
if c2 < 0:
c2 += n
m = (pow(c1, s1, n) * pow(c2, s2, n)) % n
i = 0
while 1:
if gmpy2.iroot(m + i * n, 7)[1] == True:
print(long_to_bytes(gmpy2.iroot(m + i * n, 7)[0]))
break
i += 1
return flag
c = res = str(hex(same_n_attack(n,e1,e2,c1,c2)))[2:-128]
print res
flag = ''
for i in range(0,len(res),2):
ch = res[i]+res[i+1]
flag += chr(int(ch,16))

print flag

flag{8ac9f9e3-82ba-ff7e-ac7b-235a02d891ef}

6. 结局

谁知道py的不止一个,而且越往后名次掉的越快(真卷),在比赛结束前30s,我的名次成功从rk24掉到了rk25,成功错失了进线下赛的资格(其实也好,反正我线下啥也不会,只会自闭)。

但是,这种曲线也太**了吧。

希望前面踢掉一个。

7. 等re2与misc2出来再补

8. (updated on 10.2)

好家伙,我居然进线下赛了。

本来以为是因为前面有人没写wp或者py被发现,被踢了。结果是因为23~26名分数都一样,于是就都进了。

比赛时间10.16~10.17,刚好可以逃掉寝室文化节的大寝表演,快哉快哉!