前言
据说变成了PWN专场,不过在CRYPTO大佬和RE大佬的发挥下,最后拿到密码三血排名12,拿到决赛的入场券,希望我队的pwn师傅能早日成长起来。
web
ezdotso
源码中说明 第一,不能有0-9a-zA-Z /*之外的字符 第二,这个字符串以a-zA-Z开头,中间有空格,0-9a-zA-Z/*结尾
直接构造
http://7dcccb1f119149a2ba345d9c2ef3144b4d955441e0084ff7.game.ichunqiu.com/?action=cmd&cmd=ls /就能读目录
存在flag
构造payload
http://7dcccb1f119149a2ba345d9c2ef3144b4d955441e0084ff7.game.ichunqiu.com/?action=cmd&cmd=cat /flag
读到flag
flag{b99fdc7e-b57c-4f3b-9cd1-cd63ce438920}
reverse
Code_Interpreter
简单的vm题,简述如下: 程序通过读取 code
文件进行相应的解析,总共用到了4个寄存器(可以这么认为),最后根据 bytecode
写出加密过程,解三元一次方程组,列好约束条件,利用 z3
可解比较简单。
bytecode如下:
代码语言:javascript复制op in1 in2
09 04 04 data[in1]^=data[in2] r4 =0
09 00 00 data[in1]^=data[in2] r0 = 0
08 01 00 data[in1]=data2[in2 dword_6024BC] r1=d0 first
08 02 01 data[in1]=data2[in2 dword_6024BC] r2=d1 second
08 03 02 data[in1]=data2[in2 dword_6024BC] r3=d2 thrid
06 01 04 data[in1]=data[in1]>>in2 r1=r1>>4 high byte
05 01 15 data[in1]*=in2 r1*=0x15
07 00 01 data[in1]=data[in2] r0=r1
04 00 03 data[in1]-=data[in2] r0-=r3
01 6B CC 7E 1D dword_6020A0[ dword_6024B8]=1d7ecc6b dword_6024B8 = 3 d3=1d7ecc6b
08 01 03 data[in1]=data2[in2 dword_6024BC] r1=d3=1d7ecc6b
04 00 01 data[in1]-=data[in2] r0-=r1
02 --dword_6024B8 dword_6024B8=2
0A 04 00 data[in1]|=data[in2] r4|=r0
09 00 00 data[in1]^=data[in2] r0=0
08 01 00 data[in1]=data2[in2 dword_6024BC] r1=d0
08 02 01 data[in1]=data2[in2 dword_6024BC] r2=d1
08 03 02 data[in1]=data2[in2 dword_6024BC] r3=d2
06 03 08 data[in1]=data[in1]>>in2 r3=r3>>8
05 03 03 data[in1]*=in2 r3*=3
07 00 03 data[in1]=data[in2] r0=r3
03 00 02 data[in1] =data[in2] r0 =r2
01 7C 79 79 60 dword_6020A0[ dword_6024B8]=6079797c dword_6024B8 = 3 d3=6079797c
08 01 03 data[in1]=data2[in2 dword_6024BC] r1=d3=6079797c
04 00 01 data[in1]-=data[in2] r0-=r1
02 --dword_6024B0 dword_6024B8 = 2
0A 04 00 data[in1]|=data[in2] r4|=r0
09 00 00 data[in1]^=data[in2] r0=0
08 01 00 data[in1]=data2[in2 dword_6024BC] r1=d0
08 02 01 data[in1]=data2[in2 dword_6024BC] r2=d1
08 03 02 data[in1]=data2[in2 dword_6024BC] r3=d2
06 01 08 data[in1]=data[in1]>>in2 r1=r1>>8
07 00 01 data[in1]=data[in2] r0=r1
03 00 02 data[in1] =data[in2] r0 =r2
01 BD BD BC 5F dword_6020A0[ dword_6024B8]=5fbcbdbd d3=5fbcbdbd
08 01 03 data[in1]=data2[in2 dword_6024BC] r1=d3=5fbcbdbd
04 00 01 data[in1]-=data[in2] r0-=r1
02 --dword_6024B8 =2
0A 04 00 data[in1]|=data[in2] r4|=r0
00 exit
result:
check:
dword_6024B0==0
first=94
second=94
third=94
exp如下:
代码语言:javascript复制# (d0>>4)*0x15-d2-0x1d7ecc6b =0
# (d2>>8)*3 d1-0x6079797c =0
# (d0>>8) d1-0x5fbcbdbd =0
from z3 import *
s = Solver()
a = [BitVec("a%d"%i,32) for i in range(3)]
s.add(((((a[0]>>4))*0x15-a[2]-0x1d7ecc6b)==0))
s.add((((a[2]>>8))*3 a[1]-0x6079797c)==0)
s.add((((a[0]>>8)) a[1]-0x5fbcbdbd)==0)
s.add((a[0]&0xff)==0x5e)
# s.add((a[1]&0xff)==0x5e)
s.add((a[1]&0x0ff0000)==0x5e0000)
print s.check()
m=s.model()
magic=[]
for i in a:
magic.append((m[i].as_long()))
print magic
#['0x5e5f5e70', '0x5f5e5e5f', '0x5e5e5f88']
#['0x5e5f5e5e', '0x5f5e5e5f', '0x5e5e5f5e']
Strange Interpreter
控制流平坦化,之前有个去混淆的脚本,由于没有环境,也就没弄。 先是尝试了下pintools,不过没跑出来,手动尝试了好久,只推出了前面两个字符,可能是脚本的问题。 我的pintools的脚本如下:
代码语言:javascript复制import subprocess
import os
import logging
import json
import string
import time
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class shell(object):
def runCmd(self, cmd):
res = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
sout, serr = res.communicate()
return res.returncode, sout, serr, res.pid
def initPin(self, cmd):
res = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
self.res = res
def pinWrite(self, input):
self.res.stdin.write(input)
def pinRun(self):
sout, serr = self.res.communicate()
return sout, serr
filename = "./strange"
cmd = "/home/jeb/Desktop/pin-3.7-97619-g0d0c92f4f-gcc-linux/pin -t "
"/home/jeb/Desktop/pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/ManualExamples/obj-intel64/inscount0.so" " -- " filename
shell = shell()
dic = string.letters '_ */' string.digits
cout_old = 624222
cur='X-NUCA{'
for i in range(32):
for s in dic:
shell.initPin(cmd)
pwd = cur s '?'*(31-len(cur))
print pwd
print len(pwd)
shell.pinWrite(pwd 'n')
sout,serr = shell.pinRun()
print sout
cout = sout.split("Count ")[1]
print cout
cout_sub= cout_old - int(cout)
cout_old = int(cout)
if cout_sub > 35 and cout_sub < 100:
cur=cur s
break
print ("current cur ", cur,"current count:",cout,"sub_count ",cout_sub)
然后带着混淆,调试了一遍,发现加密过程很简单,无非是几个xor,dump出数据便可解决。
首先搜索字符串,交叉引用到 loc_412385 中,可以看出这里便是最后的校验部分,程序使用llvm混淆,中间的过程全是无关的指令,着重关注最后那10多个基本块即可!在每个基本块的位置下断点,然后不断 F9 很容易看出程序的大致流程。
代码语言:javascript复制1.先是逐字节拷贝输入
2.异或数据的初始化
3.一些无关紧要的乘法运算
4.对前0x10字节进行xor
5.再次生成xor数据
6.对后0x10字节进行xor
7.最后同12345abcdefghijklmnopqrstuvwxyz进行比较,可以看出都是xor运算
最后一个xor如图
exp如下:
代码语言:javascript复制dic = '012345abcdefghijklmnopqrstuvwxyz'
dic_list=list(dic)
xor1=[0x68,0x1C,0x7C,0x66,0x77,0x74,0x1A,0x57,0x06,0x53,0x52,0x53,0x02,0x5D,0x0C,0x5D]
xor2=[0x04,0x74,0x46,0x0E,0x49,0x06,0x3D,0x72,0x73,0x76,0x27,0x74,0x25,0x78,0x79,0x30]
xor3=[0x68,0x1C,0x7C,0x66,0x77,0x74,0x1A,0x57,0x06,0x53,0x52,0x53,0x02,0x5D,0x0C,0x5D]
print len(xor1)
flag1=""
for i in range(16):
flag1 =chr(xor1[i]^ord(dic[i]))
print flag1
flag2=""
for i in range(16):
j=i 16
flag2 =chr(xor2[i]^ord(dic[j])^xor3[i]^ord(dic[i]))
print flag2
print flag1 flag2
crypto
Warm Up
源码分析后发现是rsa加密的套路 原本认为是在e处存在攻击点 收来仔细查看数据包发现数据流0和3中的N值相同 可以进行共模攻击 exp如下:
代码语言:javascript复制import gmpy2 as gm
from Crypto.Util.number import long_to_bytes
N1 = 25118186052801903419891574512806521370646053661385577314262283167479853375867074736882903917202574957661470179148882538361560784362740207649620536746860883395110443930778132343642295247749797041449601967434690280754279589691669366595486824752597992245067619256368446164574344449914827664991591873150416287647528776014468498025993455819767004213726389160036077170973994848480739499052481386539293425983093644799960322581437734560001018025823047877932105216362961838959964371333287407071080250979421489210165485908404019927393053325809061787560294489911475978342741920115134298253806238766543518220987363050115050813263
N2 = 16469436076891819107430664586570790058365332532674438789146675997314595491187244459383921424835032067061885275554735557145712521498253296163910390306330135855302922157272936907898045006260883274333834229418152155694295570782207999565052765330228242362968933298758811404031322069181362855243705838799645685066332172969401743211750904509226291946662578751991715996103303976647730874845283020815000321892678220724802450248872234664036667264022384588371373249390642053539194423282694248940736528696713895935252137917260856321114370743803866601761211552228903425850365457360876898940583221394582723557605309072232855822121
N3 = 25118874053328546753024263989563415727502048075025991833569501205632242337113077901532332374775395419348348701048189408092632079814832363732010926177912082562964016670890936281050864496155721672281093344082281963638371977758361202131970609490512245265719538879695944721744492357697438865016952531556200322390888505552979421131419142724258271230059422420336363879787201072494558351266967920357858873458121748582985640375604986741727501058494951533532341125506734541216305271046143705754799910729045435564538502962145048652820879590895993225869189429946329168385872964357133780290864454638364009252548494323438022231349
N4 = 25118186052801903419891574512806521370646053661385577314262283167479853375867074736882903917202574957661470179148882538361560784362740207649620536746860883395110443930778132343642295247749797041449601967434690280754279589691669366595486824752597992245067619256368446164574344449914827664991591873150416287647528776014468498025993455819767004213726389160036077170973994848480739499052481386539293425983093644799960322581437734560001018025823047877932105216362961838959964371333287407071080250979421489210165485908404019927393053325809061787560294489911475978342741920115134298253806238766543518220987363050115050813263
N5 = 22890921296489391468723563207482439368715048528954857727696611997213849453925407639478311064849002092841332187029922829503732594819405334557899018193836573827538367732876315261107786375883032702336369949813383359822945447348738639898488349249930794685147680602369574583272233186638639006722932514492412473499671240672786609392623108668740611409192410353088792926863759136574234682712437658167544420388503462191966664297486016864300587100339017032869018550693788156823952834586915180769842001379726271815407042736414817319930070363123671954772200618698975099285175523273493454655068815092164026790575552599814897599019
N6 = 13610734669757105262564498565903016628884897465642188626977712600469428943454859353288561953332071112838192895353839306728698072861317475483364599428738408203420859463545743033507453999902768670963760117002226738834212826866972790759618857592183639430006129961804969344458099739275801744555852908477399106370903274847008168191406212026496201683437988789750311357127030874197256108087969060429116893649257007863251857384220793898187863784143099430027004383026281731367512474585221423627626454894508617409600974924819458907176960087389776551021286749078138520414178131682409288175569603840517742966654020297053280120421
Ns = [N1, N2, N3, N4, N5, N6]
for i in range(6):
for j in range(i 1, 6):
print i, j, gm.gcd(Ns[i], Ns[j])
#通过这个循环发现了有两个N是一样的
e1 = 7669
e2 = 6947
c1 = 22917655888781915689291442748409371798632133107968171254672911561608350738343707972881819762532175014157796940212073777351362314385074785400758102594348355578275080626269137543136225022579321107199602856290254696227966436244618441350564667872879196269074433751811632437228139470723203848006803856868237706401868436321225656126491701750534688966280578771996021459620472731406728379628286405214996461164892486734170662556518782043881759918394674517409304629842710180023814702447187081112856416034885511215626693534876901484105593275741829434329109239483368867518384522955176807332437540578688867077569728548513876841471
c2 = 20494665879116666159961016125949070097530413770391893858215547229071116025581822729798313796823204861624912909030975450742122802775879194445232064367771036011021366123393917354134849911675307877324103834871288513274457941036453477034798647182106422619504345055259543675752998330786906376830335403339610903547255965127196315113331300512641046933227008101401416026809256813221480604662012101542846479052832128788279031727880750642499329041780372405567816904384164559191879422615238580181357183882111249939492668328771614509476229785062819586796660370798030562805224704497570446844131650030075004901216141893420140140568
def sameModula(n, e1, e2, c1, c2):
g, x1, x2 = gm.gcdext(e1, e2)
if x1 < 0:
c1 = gm.invert(c1, n)
x1 = -x1
if x2 < 0:
c2 = gm.invert(c2, n)
x2 = -x2
p = gm.powmod(c1, x1, n) * gm.powmod(c2, x2, n) % n
return p
m = sameModula(N1, e1, e2, c1, c2)
print m
print long_to_bytes(m)
得到flag FLAG{g00dLuck&Hav3Fun}
baby_crypto
题目
代码语言:javascript复制The 26 letters a, b, c, ..., y, z correspond to the integers 0, 1, 2, ..., 25
len(key_a) = m
len(key_k) = n
c[i] = (p[i] * key_a[i % m] key_k[i % n]) % 26
p is plain text, only lowercase letters are refered to.
c is encrypted text
I have appended the flag at the end of plain text, the format of which is like 'flagis......'
Now you have the encrypted text, Good luck!
可以看出题目是将字母首先对应成了数字
而后使用长度分别为m和n的密钥keya和keyk对明文p进行了加密
关键点在于使用%m和%n是使密钥循环起来进行加密
这样不由得想起vigenere密码
代码语言:javascript复制首先选择一个密钥
随后循环使用密钥对密文进行加密
因此破解的原理应该与破解vigenere密码原理类似
这里就可以利用重合指数的方法来对这个多表替换的密码进行分析与破解
维吉尼亚密码破解及重合指数
这是一种破解vigenere密码很好的方法
代码语言:javascript复制在一串无规律的字母中,我们随意抽取两个字母,由于每个字母被抽到的概率相同,因此抽取的两个字母相同的概率为26*(1/26)^2=0.0385
如果是从一篇文章或者一句完整的话中抽取的概率为P(a)^2 P(b)^2 …. p(z)^2=0.0687
为了破解密钥的长度l,我们需要使用上述的重合指数
我们已经知道,维吉尼亚密码可以被分解为若干组平移密码来破译,而一个明文足够长的平移密码的重合指数接近0.0687。换言之,如果我们选取某个l值,使得分组后的密文的重合指数接近0.065,则说明选取的t值与密钥的长度是一致的。
所以这里应该先求出密钥keya和keyk长度的最小公倍数
经过爆破尝试,这里当l为6的整数倍的周期,切出来的子密文段的信息指标都很接近0.065
因此这里推测密钥keya和keyk长度的最小公倍数l为6
在求得密钥长度之后,通过穷举密钥字母的每一种可能取值(a到z总共26种),并且针对每一行求其在某一取值下重合指数,重合指数最高的情况下该行最有可能为明文原文,此时的穷举结果即为密钥字母。
由此就可以得到密钥
从而对密文进行解密
exp如下: