2019UNCTF競技賽部分writeup

Reversepython

unctf_babyre2算法

這題flag分爲兩部分,第一部分每四個字符一組打包成int後,每次把四個int傳入函數,後三個參數異或後先以每位爲索引查表,將新數據進行循環移位、異或,將結果與第一個參數異或。此操做進行了26次,經過最後的一組結果能夠慢慢倒推回去。第二部分是對字符串進行常規的異或操做與目標串比較。api

腳本:數組

#include<stdio.h> #include<strings.h>

int main(){ int i,j; unsigned int v40,v41,v42,v43,v44,v39,v1,v1a,v1b,v1c,v1d,part1d,index,v1rop; int v5[]={1,5,4,2,3,0}; char part2[32]={0}; char part1[17]={0}; char c[]={0x2C,0x21,0x1e,0x73,0x32,0x12,0x72,0x37,0x10,0x38,0x38,0x1,0x1D,0x6B,0x66,0x79,0x79,0x26}; unsigned int road[30]={0}; unsigned int map[]={0X1B,0X5D,0X42,0X2B,0X0D,0X05,0X48,0XE6,0X35,0X16,0X9E,0XB5,0XBB,0XE3,0X24,0X0F,0X13,0XC0,0X59,0X96,0X5A,0X12,0X2B,0XE0,0X8F,0X21,0X8C,0X52,0XDE,0X92,0X12,0X84,0XA3,0XE2,0X6E,0X7B,0X76,0XA2,0X0F,0X51,0X93,0XA9,0X78,0XAB,0X5F,0X5E,0X16,0X82,0X72,0X82,0X26,0XD1,0X26,0XD4,0X09,0XBF,0X74,0XDA,0XA7,0X3E,0X99,0X02,0X65,0XC3,0XB3,0XAD,0XE0,0X5A,0XAB,0X7A,0X83,0X93,0X3F,0XA4,0X11,0X3D,0X8E,0X0D,0XDF,0X5A,0X71,0X08,0X3A,0XC8,0XF4,0X90,0X16,0X1B,0X88,0XC6,0X50,0X6F,0XD1,0XA4,0XB3,0X73,0X7B,0X82,0XBF,0XB2,0X5F,0X94,0XDE,0XCA,0X5A,0X5E,0XAB,0X25,0XBE,0X8C,0X1B,0X80,0X65,0X9E,0XEC,0X5A,0X37,0X2A,0X75,0X2C,0X2D,0XBA,0X56,0XD0,0XBA,0X3A,0XB6,0X94,0X81,0X70,0X87,0X75,0X3D,0X48,0X63,0X7D,0X52,0X81,0X39,0XB5,0X23,0XD4,0XD3,0XDD,0X4B,0XD9,0XB8,0X35,0XA3,0XCA,0X40,0X77,0X52,0X7C,0X9E,0X6C,0X42,0XD8,0X53,0X6F,0XEA,0X2E,0X0C,0X9A,0XF3,0X2A,0X6A,0XD5,0XEA,0X6B,0X93,0X2F,0X18,0X5C,0XBE,0X96,0XB4,0X26,0X0F,0XDB,0X9F,0X07,0X30,0XAF,0X93,0X34,0X27,0X8E,0X0A,0XCA,0X53,0XB7,0XC9,0X8F,0X9B,0X40,0X87,0X54,0X50,0X53,0X1E,0X55,0X06,0X04,0X87,0XC9,0X5E,0X78,0XA0,0X3F,0X66,0X08,0XB0,0X09,0X6E,0X83,0XE5,0X6C,0X23,0XE6,0X74,0X83,0X01,0XA4,0X7F,0X62,0X39,0X09,0X94,0X32,0XD3,0X88,0X93,0X61,0XC2,0XC6,0X61,0X6B,0X28,0XC7,0X61,0XDD,0XDB,0X90,0XA9,0XD5,0XD8,0X8A,0XA4,0XA0,0X65,0XC1,0X35,0X41,0XBA,0XCF,0X4A,0X47,0XCA,0XAF,0X51,0XE1,0X72,0X5A,0XBF,0X1E,0XB3,0X7A,0X80,0XF2,0X7A,0XCB,0X25,0XE6,0X98,0X96,0X1B,0X53,0X44,0XD8,0X3C,0XAC,0X12,0XB1,0X64,0X47,0X35,0X00,0XFF,0XFF,0XFF,0XFF}; for(i=0;i<18;i++){ c[i]^=0x45; } for (j=17;j>=0;j--){ part2[6*(j/6)+v5[j%6]]=c[j]; } for (j=0;j<18;j++){ part2[j]^=j; } //part1:
 road[26]=0XCC227F52; road[27]=0X5227AA48; road[28]=0X34725FD0; road[29]=0X0F276B39; for(i=25;i>=0;i--){ index=road[i+1]^road[i+2]^road[i+3]; v1=(map[index>>24]<<24)|(map[(index>>16)&0xFF]<<16)|(map[(index>>8)&0xFF]<<8)|map[index&0xFF]; v1rop=((v1>>6)|(v1<<26))^((v1>>8)|(v1<<24))^((v1<<10)|(v1>>22))^((v1<<12)|(v1>>20)); road[i]=road[i+4]^v1rop; } strncpy(part1,(char *)road,16); printf("UNCTF{%s-%s}",part1,part2); return 0; }

 

UNCTF{1_th1nk_re_e4sy!-Wh4t_aB0ut_yoU233?}app

 

666函數

輸入18位串,通過變換後和目標串izwhroz""w"v.K".Ni對比,這個能夠逆推回去。工具

 

#include<stdio.h>

int main(){ char i; char target[]="izwhroz\"\"w\"v.K\".Ni"; for(i=0;i<18;i+=3){ target[i]=(target[i]^18)-6; target[i+1]=(target[i+1]^18)+6; target[i+2]=(target[i+2]^18)^6; } puts(target); return 0; }

 

輸出:unctf{b66_6b6_66b}ui

 

BabyXorspa

這個須要用到一些動態調試技巧。翻譯

用OD載入,先運行起來,在待輸入時按暫停。點擊K查看堆棧調用,發現了ReadConsoleA這個函數,但這是系統api,沒有價值,因此右擊,顯示調用,再右擊選擇執行到返回,再稍微往下走出retn,就能見到程序的調用代碼。選中的call就是剛纔的api。下面就是對輸入的處理了。

 

 

緊接着有段代碼讀取輸入:

 

 

 再日後rern出去,有三個函數生成了flag:

 

 

 

 

 

flag{2378b077-7d6e-4564-bdca-7eec8eede9a2}

 

unctf_easy_Maze

IDA分析得知main裏有三個主要函數,step0和step1用來生成一張7X7的地圖,step2讀取鍵位,而且判斷當前地圖是否爲1.

 

生成地圖的函數算法過於複雜,但能夠經過動態調試看數據來直接看到結果。

在step2下斷,程序運行到這裏後進call,找到a1的地址,在數據窗口找到,把49個字節複製出來,轉換成地圖便可。

 

UNCTF{ssddwdwdddssaasasaaassddddwdds}

 

奇怪的數組

IDA查看後得知要求輸入格式爲flag{32位數據},其中32位數據爲0-9和a-f。每次兩個數字轉成16進制數後和checkbox裏的數比較,循環15次。因此把checkbox的數翻譯成小寫便可。

 

 

flag{ad461e203c7975b35e527960cbfeb06c}

easyvm

vm把函數入口和調用過程作的很複雜,通過判斷後下圖黃色代碼本來是一個函數,功能是提供其餘函數的入口。

 

 

把裏面所有函數下斷,看得出程序源碼大概是這樣的:

#include<stdio.h>

int main(){ int i; unsigned char a16=0,a17=0; char input[]="66666666666666666666666666666666"; unsigned char c[32]={0xF4,0x0A,0xF7,0x64,0x99,0x78,0x9E,0x7D, 0xEA,0X7B,0X9E,0X7B,0X9F,0X7E,0XEB,0X71, 0XE8,0X00,0XE8,0X07,0X98,0X19,0XF4,0X25, 0XF3,0X21,0XA4,0X2F,0XF4,0X2F,0XA6,0X7C}; for(i=0;i<32;i++){ a16=input[i]; a16-=i; a17=a16 ^ a17; a16=-51; a16=a16^a17; if(a16==c[i]){ puts("YES"); a17=a16; } else{ puts("NO"); break; } } return 0; }

 

寫出相應的解密腳本:

#include<stdio.h>

int main(){ int i; unsigned char a16=0,a17=0; unsigned char c[32]={0xF4,0x0A,0xF7,0x64,0x99,0x78,0x9E,0x7D, 0xEA,0X7B,0X9E,0X7B,0X9F,0X7E,0XEB,0X71, 0XE8,0X00,0XE8,0X07,0X98,0X19,0XF4,0X25, 0XF3,0X21,0XA4,0X2F,0XF4,0X2F,0XA6,0X7C}; printf("9"); for(i=1;i<32;i++){ printf("%c",(c[i]^(-51)^c[i-1])+i); } return 0; }

 

UNCTF{942a4115be2359ffd675fa6338ba23b6}

 

 

 

 

WEB

 checkin

右鍵查看源代碼,查看app.03bc1faf.js,發現聊天窗提供了一些指令,嘗試/flag無效果後又看到了/calc指令,能夠進行數學計算,嘗試了一些命令後發現fs部分命令可用,進行同步讀取目錄:
/calc require('fs').readdirSync('../')
發現根目錄下有flag,再用readdirSync('../flag')查看目錄時報錯,說明flag不是目錄是文件。
因此進行同步讀取文件:
/calc require('fs').readFileSync('../flag'),返回了一個文件對象,從新用burp抓包能夠看到對象的具體內容,ascii解碼後就是flag

 

 

 

#!python3 flag=[102,108,97,103,123,48,101,52,100,49,57,56,48,101,102,54,102,56,97,56,49,52,50,56,102,56,51,101,56,101,49,99,54,101,50,50,98,125,10] for i in flag: print(chr(i),end='')

flag{0e4d1980ef6f8a81428f83e8e1c6e22b}

 

 

 

MISC

信號很差我先掛了

用stegsolve打開apple.png, 選擇data extract,在rgb最低位有位隱寫,把它提取出後獲得一個壓縮包,但這個壓縮包後面還有一段垃圾數據,使得沒法解壓,直接用binwalk強制解壓,獲得一張圖片pen。想到了PPAP這首歌,應該是把兩張圖片結合,stegsolve嘗試了imege_combiner的xor, and ,add 後都不行,想到盲水印也是須要兩張圖,用工具BlindWaterMark,得出flag:

unctf{9d0649505b702643}

快樂遊戲題

 

 

 

親愛的

用binwalk掃一下得知文件隱寫了一個zip,zip有密碼,旁邊的提示寫着qq音樂和一個日期,猜想是在那個時間點的一條評論。先找到李現唱的海闊天空https://c.y.qq.com/base/fcgi-bin/u?__=YTLCV4E,翻評論發現密碼,解壓後是一張圖片,圖片也有隱寫內容,提取後在裏面的word/media裏有張圖片,寫着flag.

UNCTF{W3_L0v3_Unctf}

 

 

Think

這題是一個python的混淆代碼,沒有徹底讀懂,但能夠看一些關鍵操做。解密代碼是

chr((ord(__l['key'][(__l['i'] % len(__l['key']))]) ^ ord(__l['encrypted'][__l['i']].decode('base64').decode('hex')),能夠看到是把後面的base64解密後和key循環異或,i是索引。據此寫出代碼:

#!python2 import sys enc=['MTM=', 'MDI=', 'MDI=', 'MTM=', 'MWQ=', 'NDY=', 'NWE=', 'MDI=', 'NGQ=', 'NTI=', 'NGQ=', 'NTg=', 'NWI=', 'MTU=', 'NWU=', 'MTQ=', 'MGE=', 'NWE=', 'MTI=', 'MDA=', 'NGQ=', 'NWM=', 'MDE=', 'MTU=', 'MDc=', 'MTE=', 'MGM=', 'NTA=', 'NDY=', 'NTA=', 'MTY=', 'NWI=', 'NTI=', 'NDc=', 'MDI=', 'NDE=', 'NWU=', 'MWU='] key='unctf'

for i in range(38): sys.stdout.write(chr(ord(key[i%5])^ord(enc[i].decode('base64').decode('hex'))))

 

flag{34a94868a8ad9ff82baadb326c513d40}

 

不單單是RSA

對公鑰提取出N1, N2, E,摩斯電碼用morse code reader識別出C1,C2,把N在http://www.factordb.com/ 分解,得

P1=95652716952085928904432251307911783641637100214166105912784767390061832540987

Q1=107527961531806336468215094056447603422487078704170855072884726273308088647617

P2=89485735722023752007114986095340626130070550475022132484632643785292683293897

Q2=95652716952085928904432251307911783641637100214166105912784767390061832540987

寫腳本:

#!python2 import gmpy2 from Crypto.Util.number import *

from Crypto.PublicKey import RSA f = open("pubkey1.pem", "r") key = RSA.importKey(f.read()) n1=key.n e1=key.e print ('N1=',n1) print ('E1=',e1) #而後分解N f = open("pubkey2.pem", "r") key = RSA.importKey(f.read()) n2=key.n e2=key.e print ('N2=',n2 ) print ('E2=',e2) p1=95652716952085928904432251307911783641637100214166105912784767390061832540987 q1=107527961531806336468215094056447603422487078704170855072884726273308088647617 p2=89485735722023752007114986095340626130070550475022132484632643785292683293897 q2=95652716952085928904432251307911783641637100214166105912784767390061832540987 phi1=(p1-1)*(q1-1) c1=4314251881242803343641258350847424240197348270934376293792054938860756265727535163218661012756264314717591117355736219880127534927494986120542485721347351L d1=gmpy2.invert(e1,phi1) m1=gmpy2.powmod(c1,d1,n1) print hex(m1)[2:].decode('hex') phi2=(p2-1)*(q2-1) c2=485162209351525800948941613977942416744737316759516157292410960531475083863663017229882430859161458909478412418639172249660818299099618143918080867132349L d2=gmpy2.invert(e2,phi2) m2=gmpy2.powmod(c2,d2,n2) print hex(m2)[2:].decode('hex')

UNCTF{ac01dff95336aa470e3b55d3fe43e9f6}

相關文章
相關標籤/搜索