o_CTF UIUCTF 2024
Crypto
Without a Trace
u1,u2,u3,u4,u5がそれぞれ順番にフラグの5文字分になっている
(u1, u2, u3, u4, u5) = (1,1,1,1,1), (1,1,1,1,2), (1,1,1,2,1), (1,1,2,1,1), (1,2,1,1,1), (2,1,1,1,1)
を取ってきて、それぞれの差分を取るとu1,u2,u3,u4,u5の値が求まるので、復元するとフラグが求まる
Determined
行列を調べると
$ \begin{pmatrix}p & 0 & a_0 & 0 & a_1 \\ 0 & a_2 & 0 & a_3 & 0 \\ a_4 & 0 & a_5 & 0 & a_6 \\ 0 & q & 0 & r & 0 \\ a_7 & 0 & a_8 & 0 & 0 \end{pmatrix}
みたいな形になることがわかる($ a_xは入力可能な値)
この行列式が帰ってくるので、いい感じに0と1をおいて、$ qのみ or $ rのみとなる入力を生成する
こうなるときの$ a_xの値は
$ r: (a_0, a_1, a_2, a_3, a_4, a_5, a_6, a_7, a_8) = (0,1,1,0,0,1,0,1,0)
$ q: (a_0, a_1, a_2, a_3, a_4, a_5, a_6, a_7, a_8) = (0,1,0,1,0,1,0,1,0)
あとは$ pも求めてRSA暗号を復号する。
X Marked the Spot
saltが8文字で、FLAGが48文字で、saltを繰り返してxorを取っているので、uiuctf{}の部分を使ってsaltを特定、全部のflagを戻すと解ける
Naptime
フラグの1文字づつを8bitの値に変更して、その位置にある$ aの値を足しているだけなので、$ n!通りを全部試して全てのctに対して適切になる$ aの順列を求めて8bitの値を復元して文字に直す
code: solve.py
n = 8
ct = 273896, 179019, 273896, 247527, 208558, 227481, 328334, 179019, 336714, 292819, 102108, 208558, 336714, 312723, 158973, 208700, 208700, 163266, 244215, 336714, 312723, 102108, 336714, 142107, 336714, 167446, 251565, 227481, 296857, 336714, 208558, 113681, 251565, 336714, 227481, 158973, 147400, 292819, 289507 def main():
bitstrings = []
for c in ct:
count = 0
for i in range(2**n):
tmp = 0
for j in range(n):
if(i & (1 << j)):
if tmp == c:
count += 1
bitstrings.append(bin(i)2:.zfill(8)) break
val = []
for z in bitstrings:
s = ""
for i in range(len(z)):
val.append(s)
if chr(int(val0,2)) == 'u' and chr(int(val1,2)) == 'i': print("".join([chr(int(vali,2)) for i in range(len(val))])) return
a_ = [a[pii] for i in range(len(b))] dec(ct, a_, pi, n)
OSINT
An Unlikely Partnership
Google検索したらFlagが出てきた 多分非想定
Night
角が生えてる特徴的な建物があったので、Google Lensで検索すると出てくる。
隣にあるビルとの位置関係を考えたときに想定される位置をGoogle Mapで探すと適当な橋が出てくる。
この橋の名前を見るのが相当難しいのでGoogle Map力が必要
Rev
Summarize(未Solve)
全部復元してコード書いたんだけどなんか通らない Ghidraがある関数だけvoidでanalyzeしてたのが関係合ったりするかなあ?
Ghidraに頼らないでRevする力も持ってたほうが良さそう
code: solve.cpp
using namespace std;
const int mn = 100000000;
const int mx = 1000000000;
bool inrange(int x){
return mn <= x && x < mx;
}
bool check(unsigned int a,unsigned int b, unsigned int c, unsigned int d, unsigned int e, unsigned int f){
if(a < mn || b < mn || c < mn || d < mn || e < mn || f < mn)return 0;
if(a < mx && b < mx && c < mx && d < mx && e < mx && f < mx){
if (
((int)(((b+d)) % (unsigned int)a) == 540591164) &&
((a+b) % 17381917 == 9166034) &&
((3*a-2*b) % (a^d) == 556569677) &&
((a-b+c) % 17492321 == 4139449) &&
((b & (c+a)) % 28194 == 12734) &&
((c^(d+f)) % 1893928 == 1279714) &&
((e-f) % 18294018 == 17026895) &&
((e+f) % 48328579 == 23769303)
){
return 1;
}else{
return 0;
}
}else{
return 0;
}
}
// 540591164 < a
// d < 536870912
// 556569677 < a^d
//
// a: 1xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// d: 0xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//
string str = "";
void phase5(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int f){
cout << a << " " << b << " " << c << " " << d << " " << f << endl;
// ((e-f) % 18294018 == 17026895) &&
// ((e+f) % 48328579 == 23769303)
for(int i = 23769303; mx+2 >= i; i+=48328579){
unsigned int e = i-f;
cout << (e-f)%18294018 << endl;
if(inrange(e) && ((e-f)%18294018 == 17026895)){
str = "uiuctf";
cout << "uiuctf{" << a << b << c << d << e << f <<"}" << endl;
}
}
}
void phase4(unsigned int a, unsigned int b, unsigned int c, unsigned int d){
cout << a << " " << b << " " << c << " " << d << endl;
// ((c^(d+f)) % 1893928 == 1279714) &&
for(int i = 1279714; mx*2 >= i; i+=1893928){
unsigned int f = (i^c)-d;
if(inrange(f)){
phase5(a,b,c,d,f);
}
}
}
void phase3(unsigned int a, unsigned int b, unsigned int d){
cout << a << " " << b << " " << d << endl;
// ((a-b+c) % 17492321 == 4139449) &&
// ((b & (c+a)) % 28194 == 12734) &&
for(int i = 4139449; mx*2 > i; i+=17492321){
unsigned int c = i+b-a;
if(inrange(c) && (((b&(c+a)) % 28194) == 12734)){
phase4(a,b,c,d);
}
}
}
void phase2(unsigned int a, unsigned int x1){
// ((a+b) % 17381917 == 9166034) &&
// ((3*a-2*b) % (a^d) == 556569677)
if(a%1000000 == 0)cout << a << " " << x1 << endl;
for(int i = 9166034; mx*2 >= i; i+=17381917){
unsigned int b = i-a;
unsigned int d = x1-b;
if(a==d)continue;
if(inrange(b) && inrange(d) && ((3*a-2*b)%(a^d) == 556569677)){
phase3(a,b,d);
}
}
}
void phase1(){
// ((int)(((b+d)) % (unsigned unsigned int)a) == 540591164) &&
for(int i = 540591165; mx >= i; i++){
if(i%100000000 == 0)cout << "!!" << i << endl;
for(int j = 0; 3 > j; j++){
unsigned int a = i;
phase2(a, a*j+540591164);
}
}
}
void solve(){
phase1();
}
int main(){
solve();
cout << "ans: " << str << endl;
}
感想
なんでICPC地区予選直前なのに出てるの?