2019UNCTF竞技赛部分writeup
Posted cnnnnnn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019UNCTF竞技赛部分writeup相关的知识,希望对你有一定的参考价值。
Reverse
unctf_babyre2
这题flag分为两部分,第一部分每四个字符一组打包成int后,每次把四个int传入函数,后三个参数异或后先以每位为索引查表,将新数据进行循环移位、异或,将结果与第一个参数异或。此操作进行了26次,通过最后的一组结果可以慢慢倒推回去。第二部分是对字符串进行常规的异或操作与目标串比较。
脚本:
#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?}
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}
BabyXor
这个需要用到一些动态调试技巧。
用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}
以上是关于2019UNCTF竞技赛部分writeup的主要内容,如果未能解决你的问题,请参考以下文章
2021安全范儿高校挑战赛ByteCTF线上赛部分Writeup