现充|junyu33

强网杯出土记

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

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

1. 签到

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

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

2. Lihua's for

第一步查壳:

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

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签到题)

#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

给定:

n1=20663949646446787716947370247427064802032290773674573417491154934657966734874241036307633567695175131014840617208051931753476223149652427133485160771068994073566431652969243962290116898345337189704974833817335135391974497754670322430159624252007005736522065638860351992074099453212550475552692645688800084354832716662142860413158369020005830095049988807931794736876563293916525328174812726514626029103506607813186690909585870115364600969148482617083817273910020722354923244093624032174432568413187131385994452769295894606345768596899824635672699945050103814681553981019917552667794514804359500108947102234376726009329
n2=23260834024376640092536888922041147168387702014814910549469730354688848760379274203088716649609675449936234732528778557041701524981200368996310064584479657042098426164366286670115392015865853892816983885530312074073396422301009513106258655315791720535737587913264728919869055970993613641008348186263870234072422880033882864603438907070864271470483691729705421547143623305055532339107777314310976947392833395180922324243244784018964736826235018388498516438612962123562977736924674510730898077787055367234786519915374446506561992135856904927351307275140543635152771670410211235702283822782412971646092584646758107766061
c1=20522772249591436865905796103232542494211695376973377722875606678999899690405480809231671346489821878050354380591999935960795888483664473952207298504196203830543208477229162177648586683957831016664569242538775928728009699300145355818417233892295367828930893733774091897666206696635744262884229680137381841581000794056156842812583057103472764486608022028638288161256424936523444974815727764620634174112474612238992061186937613171878635903455700636894570504376153482600057655480654731180740098435209814585459376319844315388048636156465832997913885636776523217188604040216732137108997444787157007665652718553013424347649
c2=18715009944766815149492560645051626329204114049927707292306481018724323433701970253541495090244787378826569549885480491764057526828531429033378143426272248940256432423939977805246742287886281853484696625486522535042794403288199393432900065504766428665320682811338887618389589263597065738414638013423594446322359052784842619755053094028050245325637698678444632860097510081832077842610716042473697478416213915805481704537884611126069907812621750817901278803326304784057145916721693930579344441283586458621033705530309835431139751025999089707480829034535026967779441379062426254038310930863215188888662357133997908688736
e=65537

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

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一道题才能稳住线下赛的资格。

于是我们有:

n=96722669749951212913756678234358651184134068407812470434435916603156818917545841439779031943800634250032106764154804309935557678512858630048212204696471487762160744924838010746445510979202735123140536599975731157563069594497905809587369126155476201977830809090473053692189364335223367147692962090288185113654598050169422517553085833257142179937154768657039042632343562454149914801329414293361879935460883633117988279426277638667508115319494914342600199690237441851088350726869553691992122821267990343643644523989413546160765907845604067031798179773495433134648132709349683621175243064236059479837244518879574919017301667066698329442453248971033564328161407342561250703168154214939772631586519304164853651
c1=66738113223447221430009739914948303261002811553064307532926788024694319846909340806982708347904688420671656410554852340732395818007063648478593071665936277836988050526188064146099581039172667768507259894363266310279948729552649788129953872816024709989260060633285022337107662251504618369065597018450927041881262189584381809106166042131798086882746986243210896131714227544235843922107304728228549916171484199199612243776469423359120753888158616202476325705252715374109256790899923317253605743212561589807498078080069511918514647943399566630574192829185904868376879831247378819590121286186417825591746918495311372015707767009078229770450338244309693800180936418605756818618708750868807720566288044943952844
c2=88330949146651042517337653740810385187361689012501792799900873279978736035790659211001047937337215121948527017022967642906632732136313750277237761910710915459733551421653259986088596828049455592613225962133163865584111828012197112528645520371075411167515961263199635568730334149461654340122507778194391601956023625429418297129608911450200836427221311442323768087256798964844787274408624548839536279704401007441198390922847003287643673183230633728790263593607595427088882078742699027563601046309308221108391158848644822374865676056755011459026909057983805069264236657111115914570543103494726584296335044897998794251877515750910330960179539465060133592380802344398038815679281272098815068185059127533110716
e1=49
e2=35

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

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

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

# 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,刚好可以逃掉寝室文化节的大寝表演,快哉快哉!