もいんもいん

ゆっぴぃ(Yuppy_orz)のメモ書き

SECCON CTF online 2017 write-up

SECCON CTF 2017にチームint0x80にて参加しました。ほかのメンバーが頑張ってくれたのであまり活躍してない。結局1問だけ。

Ps and Qs (Crypto 200)

-rw-r--r-- 1 yu yu 800 Dec 9 01:33 pub2.pub
-rw-r--r-- 1 yu yu 800 Dec 9 01:33 pub1.pub
-rw-r--r-- 1 yu yu 512 Dec 9 01:33 cipher

公開鍵っぽいもの2つとcipher。問題名から、秘密鍵1 と秘密鍵2に公約数sがあるものと想定。 とりあえず公開鍵に含まれる積を取り出す。

$ openssl rsa -noout -text -pubin -in pub1.pub Public-Key: (4096 bit)
Modulus:
    00:cf:cf:bb:ee:a7:df:14:3a:8a:c2:08:b1:aa:1d:
    2f:86:54:5a:c4:cb:58:8c:94:a3:fb:1c:14:ad:91:
    a4:f0:b9:36:15:7c:5a:4b:86:9c:18:a8:b8:64:f4:
    72:6b:f8:fc:dc:02:0c:b4:10:42:ba:c9:67:84:ab:
    7d:03:f9:37:49:47:ef:b0:bc:3d:66:58:31:97:43:
    40:15:9f:fc:3d:b7:c8:e7:4b:63:90:fd:a6:ee:c3:
    0b:81:c6:ff:62:4e:8d:3f:5b:17:bf:b7:a5:c7:ff:
    d8:ec:f4:e6:51:8b:39:3a:be:fd:dd:0f:ae:ba:43:
    08:74:6b:a6:3f:81:06:b5:9d:7e:05:89:43:a0:01:
    31:a7:d4:e5:38:c4:64:b2:70:57:76:47:ed:bc:47:
    8c:c1:ce:95:85:ef:e8:77:30:5b:3a:7c:2e:7c:44:
    db:54:75:ed:da:dc:34:5a:2c:90:a9:46:77:1c:ac:
    0a:45:4c:db:cb:46:1f:28:40:e7:61:3c:83:e9:ce:
    cc:94:03:7f:a0:9b:b9:da:a3:f1:80:56:2c:01:df:
    0b:e6:c5:1f:0c:06:e8:f0:e2:d6:e1:a5:e5:0d:0a:
    28:c3:88:11:40:77:0a:9f:45:93:41:46:b7:f3:59:
    b9:39:ce:23:f0:fa:50:7a:6f:4e:45:45:71:43:09:
    52:00:3c:20:f1:d9:7a:67:14:0b:6e:5f:cb:fb:3b:
    37:6e:4e:24:96:9a:eb:1d:48:9c:fc:72:af:4f:15:
    a4:78:8a:1a:a9:7c:89:75:6d:1d:4d:94:aa:47:e7:
    cd:3a:81:ae:cb:92:44:8c:c9:2c:77:d2:ef:57:6a:
    a0:db:c1:35:08:62:ac:cd:da:dd:bc:e8:03:57:f0:
    cd:5b:85:4d:d0:f8:c4:62:7f:e4:b7:18:b2:4e:cf:
    e1:1e:d2:4c:3b:e2:2f:00:64:3b:be:d4:ee:5e:34:
    5a:f1:76:e5:b7:6d:23:a2:f8:0e:0e:c6:f3:4e:57:
    18:c6:2a:70:fe:55:70:c2:8b:80:7b:44:f2:2e:ad:
    eb:d9:b5:ff:90:6f:6a:85:be:88:c0:c8:f6:e5:f8:
    80:a5:1f:17:f8:4d:b1:c2:ee:fe:a8:af:34:04:04:
    44:ce:d1:a3:7d:f0:e4:f5:f7:2c:c3:f5:0b:7e:42:
    7c:8c:2d:8b:61:86:ea:d7:62:f0:c4:44:b3:ca:3a:
    01:03:ed:12:a9:3b:ce:9c:ae:74:79:a2:29:eb:bc:
    0a:64:8e:aa:6f:97:e5:05:1a:66:eb:09:eb:d7:34:
    8e:92:f7:5f:12:5e:bd:c3:67:e2:a7:d1:da:77:59:
    d4:1f:ae:2e:26:35:bf:4b:7a:7f:91:be:ca:b3:ac:
    7d:05:bd
Exponent: 65537 (0x10001)
$ openssl rsa -noout -text -pubin -in pub2.pub 
Public-Key: (4096 bit)
Modulus:
    00:bb:33:cc:7f:cc:8e:ca:f3:bf:9e:d9:5c:58:37:
    92:e1:ec:6b:80:ee:87:5e:c2:06:4d:bc:f0:75:95:
    c8:34:49:23:bf:53:65:24:d4:e0:a7:55:74:c7:79:
    8c:73:b1:97:dd:2b:1b:42:05:4b:1e:49:cb:45:fb:
    f0:4e:6f:11:4c:f8:a3:65:c3:df:36:45:52:4f:77:
    82:68:03:8a:3f:a2:68:02:e9:d1:ed:bf:bb:5e:df:
    b5:a0:c3:75:37:0d:7f:10:f5:7d:ab:bd:4f:77:1d:
    ad:36:32:f0:1b:9b:ce:10:48:99:66:ee:88:2d:ab:
    17:a3:3b:78:6a:a5:f7:31:65:a5:40:51:30:0b:1d:
    f9:28:03:92:a3:ed:e9:d3:fc:9c:4d:8a:6a:06:35:
    1f:6e:f3:59:8e:8d:e2:b3:9d:3b:19:af:64:a1:71:
    6c:d1:58:26:c3:f2:4c:b1:3d:eb:72:2c:3a:03:ef:
    1d:2b:e2:d0:a5:a6:e2:10:ff:5d:01:83:67:be:3b:
    f9:9e:a2:6b:a0:06:e5:16:4a:4d:d5:5a:ab:cd:44:
    9d:e5:ce:18:64:82:5d:c1:60:e5:0d:50:9e:b0:e6:
    fe:72:3e:f1:82:68:1e:dd:b9:40:84:b8:3e:c9:e2:
    e9:43:e8:7c:b8:75:09:ab:0f:d9:b1:ca:22:c1:ce:
    af:f3:9f:ca:cf:67:29:fc:0e:05:78:67:0d:87:d7:
    f0:f9:cc:be:09:cb:3e:12:ce:b8:95:57:2a:99:79:
    d1:0b:fd:bf:af:a2:60:56:8d:8d:b1:84:be:12:b3:
    e3:19:3e:07:72:9c:e3:c1:d9:cd:82:83:ed:69:83:
    a0:63:88:03:6a:0a:70:29:4f:23:39:29:44:77:82:
    80:e7:de:9f:60:16:3a:81:50:e3:0f:f4:a4:ea:02:
    79:2c:be:83:05:ba:a2:e9:9a:fe:51:e1:7d:af:c5:
    6b:e0:d3:84:14:7b:cd:38:e9:d1:29:34:ec:71:26:
    22:21:77:73:a4:b3:85:1a:9b:0c:6c:7c:3e:01:f6:
    11:1a:1e:1a:55:7f:4e:2a:e4:a2:47:ce:9b:75:cc:
    cc:b1:81:98:25:f3:05:4a:a1:c0:55:bd:3e:23:40:
    09:3a:e2:ef:1d:0f:a5:a1:76:82:5e:fd:f7:95:07:
    02:7f:51:04:08:00:09:14:2f:0d:43:e2:f1:0c:fa:
    d2:20:81:3b:bb:90:14:d4:f4:32:5e:da:c5:38:fb:
    5e:82:b7:53:e2:ad:3b:24:60:7d:73:80:aa:64:fc:
    b9:8b:59:ea:8b:5a:73:6b:80:93:83:24:8c:ec:e0:
    b1:72:55:ea:55:9e:90:12:7f:77:8a:f6:d7:e8:a6:
    6d:ad:91
Exponent: 65537 (0x10001)

それぞれを手元のsublimetextでスペースコロン無しの16進数に加工し、公約数を求めるためにwxmaximaに食わせる。公開鍵をxとyとした。

ibase: 16;
set_display('ascii)$
x: 00cfcfbbeea7df143a8ac208b1aa1d2f86545ac4cb588c94a3fb1c14ad91a4f0b936157c5a4b869c18a8b864f4726bf8fcdc020cb41042bac96784ab7d03f9374947efb0bc3d665831974340159ffc3db7c8e74b6390fda6eec30b81c6ff624e8d3f5b17bfb7a5c7ffd8ecf4e6518b393abefddd0faeba4308746ba63f8106b59d7e058943a00131a7d4e538c464b270577647edbc478cc1ce9585efe877305b3a7c2e7c44db5475eddadc345a2c90a946771cac0a454cdbcb461f2840e7613c83e9cecc94037fa09bb9daa3f180562c01df0be6c51f0c06e8f0e2d6e1a5e50d0a28c3881140770a9f45934146b7f359b939ce23f0fa507a6f4e454571430952003c20f1d97a67140b6e5fcbfb3b376e4e24969aeb1d489cfc72af4f15a4788a1aa97c89756d1d4d94aa47e7cd3a81aecb92448cc92c77d2ef576aa0dbc1350862accddaddbce80357f0cd5b854dd0f8c4627fe4b718b24ecfe11ed24c3be22f00643bbed4ee5e345af176e5b76d23a2f80e0ec6f34e5718c62a70fe5570c28b807b44f22eadebd9b5ff906f6a85be88c0c8f6e5f880a51f17f84db1c2eefea8af34040444ced1a37df0e4f5f72cc3f50b7e427c8c2d8b6186ead762f0c444b3ca3a0103ed12a93bce9cae7479a229ebbc0a648eaa6f97e5051a66eb09ebd7348e92f75f125ebdc367e2a7d1da7759d41fae2e2635bf4b7a7f91becab3ac7d05bd;
y: 00bb33cc7fcc8ecaf3bf9ed95c583792e1ec6b80ee875ec2064dbcf07595c8344923bf536524d4e0a75574c7798c73b197dd2b1b42054b1e49cb45fbf04e6f114cf8a365c3df3645524f778268038a3fa26802e9d1edbfbb5edfb5a0c375370d7f10f57dabbd4f771dad3632f01b9bce10489966ee882dab17a33b786aa5f73165a54051300b1df9280392a3ede9d3fc9c4d8a6a06351f6ef3598e8de2b39d3b19af64a1716cd15826c3f24cb13deb722c3a03ef1d2be2d0a5a6e210ff5d018367be3bf99ea26ba006e5164a4dd55aabcd449de5ce1864825dc160e50d509eb0e6fe723ef182681eddb94084b83ec9e2e943e87cb87509ab0fd9b1ca22c1ceaff39fcacf6729fc0e0578670d87d7f0f9ccbe09cb3e12ceb895572a9979d10bfdbfafa260568d8db184be12b3e3193e07729ce3c1d9cd8283ed6983a06388036a0a70294f23392944778280e7de9f60163a8150e30ff4a4ea02792cbe8305baa2e99afe51e17dafc56be0d384147bcd38e9d12934ec712622217773a4b3851a9b0c6c7c3e01f6111a1e1a557f4e2ae4a247ce9b75ccccb1819825f3054aa1c055bd3e2340093ae2ef1d0fa5a176825efdf79507027f5104080009142f0d43e2f10cfad220813bbb9014d4f4325edac538fb5e82b753e2ad3b24607d7380aa64fcb98b59ea8b5a736b809383248cece0b17255ea559e90127f778af6d7e8a66dad91;
    g: gcd(x,y);
    p: x / g;
    q: y /g;

Shift-Enterで解を得る。予想通り公約数が1以外に存在することが分かる。

(ibase)  16
(%o3) 847796795638781450678718708
664542960446354226336422534142899480441478781\
747168340722544245493739168125415291376063352480076469305992008517388366298914\
970810765149321160596112226917023146371080685458239747986992197343482255681414\
590678694753885521068656675164266739274608505094927725285868801825
144058835115\
051061857233824816176186349372737400492228548130718029270482313906040935333159\
681273527671359469173939861889228505791626525994180917670701909816457560622922\
219797109618405842358250940062127841301193206255543580550667149741357342408703\
680375118252445296600962244008043713708516004025217199954286478272550961283413\
053789743740774140439284662596273452124779590753836094450154459078034659421366\
584354005421566290862244000178569163732971816333961711759000171156293724203334\
889496589376907683142167883476184246287660764821622298961378903818077158234683\
927321823293466245584486980446609569799420950073036635602004293246754252079757\
527610246223280774592566063422181158810677919909523144033543195999214800559998\
598003329294711989868113423468536273984117507008756542731210465222475943122324\
672467669623079721727526348599823126409108190030551584092950358235465140166515\
452377475799157617227362838246912839086733412861436353117994501342653
(%o4) 76371891247516048790280
4749669814117361530270298225094625871588939939773\
892509348006077810445741086683427253000695920011673348476297973798322806091336\
777405584801442639626925406721932533140226556519019440300864340670199686368307\
1558604936150651983194900605985872020519426387929196485962885762948045497381
35\
969737494734307362891313864027749187674251692407867312885251279302785352318725\
391842117065840058358065676707016006124478822206302825992616559261930620693061\
673348139416033418864269248381876692676529410115745518353146254670349865568255\
213560376368953292931958006941630719304442332912813624543600126197554727832190\
226632919876204677667384620275620336951964833888599634720101911051166398907898\
747710391394105753614253527704990658698844796442515669670816004761855554187277\
637871343595647487793209271354240148469085627742503649786300484610102224828274\
384484809539697728008552925590472129497180290668277790132130824141651399551803\
499770513576176720509094833332201946177880267399933460994496277590932311628302\
240154240967341858152145815276163397709272690500041597393678630136932574450837\
982593210399370333578887450410911663220219423601973078501237709613593311133945\
501455828164291429228495931943107997137587307522565029820756690578833
(%o5) 284913512680212653855266513865386078073096599862766883430646700738910134\
0082516441523
06013387824730257424020493948306306758057258850884301121494978692\
423461844365014982506562524786543661869253594964276221406581073455465432577139\
196943024870499547613221012541884442078884274519798649846353235229010727057828\
355530101191155299601996161344265180903247070557309089781820754010700442764439\
579294038745123916988133061396918981675497567581891224323730030192066306113773\
192441603153120080842140385160080268045489258767335778431393536972274336459261\
763324222538
80445694249081777712571005410284034477749618735562684652311433029
(%o6) 29756285957217824990174038832451778402099067307810847648290595
7850584316\
469769083223041479591124271401597928889149232362001674900112018112504327421349\
550764671615123999570773139646300711417355041545696721914603896976339564385555\
48934921730829103416692214221897316036431719854
7270621220707112529242378599816\
508390821279476192467163117285073505212608317620178792114086711948835216991078\
859952277600521902685611723772884946474874075783577957683680616997608353053552\
223132066497479879804034800558304093546545069950900370055324807049618301832369\
22268938782515705140754745094708066416483123932606937140087049605071066540057
(%o7) 268052892714976182888249574098409000879217373642470620179546530953506059\
96401170903273670545713193946727301443
7792256550091854421243013036188024690038\
437419581472670246778687938059324493296589209828480634846887003333992041067331\
492304815274261716101078896818759926176473155393020477940584376489082126459712\
111767869575177314947237298893540754357640976586021397801435693376364574528933\
866909385223926096855561094162338051541492626634160508146847148502135500632311\
100897874915409449457122977108447359309772349703738265190424700468671371860547\
40672979017101637673890382547484646195101031561338945685511605286410830656477

得られた数値を前回で使った genpriv.pyを少し改造して貼り付ける。 yuppy.hatenablog.com

得られる値は3つなので場当たりコメントアウトしつつ実行し、privkeyを3種作成する。

import sys

ss= 28491351268021265385526651386538607807309659986276688343064670073891013400825164415230601338782473025742402049394830630675805725885088430112149497869242346184436501498250656252478654366186925359496427622140658107345546543257713919694302487049954761322101254188444207888427451979864984635323522901072705782835553010119115529960199616134426518090324707055730908978182075401070044276443957929403874512391698813306139691898167549756758189122432373003019206630611377319244160315312008084214038516008026804548925876733577843139353697227433645926176332422253880445694249081777712571005410284034477749618735562684652311433029

pp= 29756285957217824990174038832451778402099067307810847648290595785058431646976908322304147959112427140159792888914923236200167490011201811250432742134955076467161512399957077313964630071141735504154569672191460389697633956438555548934921730829103416692214221897316036431719854727062122070711252924237859981650839082127947619246716311728507350521260831762017879211408671194883521699107885995227760052190268561172377288494647487407578357795768368061699760835305355222313206649747987980403480055830409354654506995090037005532480704961830183236922268938782515705140754745094708066416483123932606937140087049605071066540057
qq= 26805289271497618288824957409840900087921737364247062017954653095350605996401170903273670545713193946727301443779225655009185442124301303618802469003843741958147267024677868793805932449329658920982848063484688700333399204106733149230481527426171610107889681875992617647315539302047794058437648908212645971211176786957517731494723729889354075435764097658602139780143569337636457452893386690938522392609685556109416233805154149262663416050814684714850213550063231110089787491540944945712297710844735930977234970373826519042470046867137186054740672979017101637673890382547484646195101031561338945685511605286410830656477

# 以下3パターンでそれぞれ出力ファイルを作成
#p= pp
#q = qq
p = ss
q = pp
#p = ss
#q = qq

e = 65537
n = p*q

def exgcd(x,y):
    r0,r1 = x,y
    a0,a1 = 1,0
    b0,b1 = 0,1
    while r1>0:
        q1 = r0/r1
        r2 = r0%r1
        a2 = a0-q1*a1
        b2 = b0-q1*b1
        r0,r1 = r1,r2
        a0,a1 = a1,a2
        b0,b1 = b1,b2
    return a0,b0,r0

d = exgcd(e,(p-1)*(q-1))[0] + (p-1)*(q-1)
exp1 = d % (p-1)
exp2 = d % (q-1)
coef = pow(q,p-2,p)

def int2bin(d):
    t = "%x"%d
    return (t if len(t)%2==0 else "0"+t).decode("hex")

def enclen(l):
    if l<0x80:
        return chr(l)
    else:
        t = int2bin(l)
        return chr(0x80+len(t))+t

def encint(n):
    t = int2bin(n)
    return "\x02"+enclen(len(t))+t

t = "".join(map(encint,[0,n,e,d,p,q,exp1,exp2,coef]))
t = "\x30"+enclen(len(t))+t

print "-----BEGIN RSA PRIVATE KEY-----"
print t.encode("base64")[:-1]
print "-----END RSA PRIVATE KEY-----"

それぞれで以下を実行してみる。

$ openssl rsautl -decrypt -in cipher -inkey privkey-xx.pem

p = ss、q = ppとした定義で得られたprivkeyではエラーとならず成功する。(残り2組はエラーになる) 以下を得る。

SECCON{1234567890ABCDEF}

TMCTF2015 write-up

トレンドマイクロさんのTMCTF 2015に、チームint0x80にて参加しました。カウントされた1500点中500点分正解。

Cryptography-100

ろば電子さんところの「opensslでRSA暗号と遊ぶ - ろば電子が詰まっている」さんの記事を参考にコマンド叩くだけ。

% openssl rsa -text -pubin < PublicKey.pem
Public-Key: (256 bit)
Modulus:
00:b6:2d:ce:9f:25:81:63:57:23:db:6b:18:8f:12:
f0:46:9c:be:e0:cb:c5:da:cb:36:c3:6e:0c:96:b6:
ea:7b:fc
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhALYtzp8lgWNXI9trGI8S8EacvuDLxdrL
NsNuDJa26nv8AgMBAAE=
-----END PUBLIC KEY-----

 ModulesがRSA暗号における「素数の積」で、これを素因数分解することの難易度がRSAの強度に直結。...って末尾が「fc」って素数の積が偶数=片方が2、なんてあり得ない。「Where is the lost 1bit?」って馬鹿にしてるんかw末尾ビットに決まってるw

最終ビットを立てたもの(fd)として読み替えて素因数分解。msieveさんカモーン

% msieve 0x00b62dce9f2581635723db6b188f12f0469cbee0cbc5dacb36c36e0c96b6ea7bfd
% tail msieve.log | grep factor
Sat Sep 26 15:28:28 2015 prp39 factor: 279125332373073513017147096164124452877
Sat Sep 26 15:28:28 2015 prp39 factor: 295214597363242917440342570226980714417

それっぽい「素数の積」であることがわかったので、あとは秘密鍵を作成。

草野さんところの「backdoorCTF 2014 Write-up - kusano_kの日記」を元に秘密鍵のファイルを作成。

% vi genpriv.py
import sys

p = 279125332373073513017147096164124452877
q = 295214597363242917440342570226980714417

e = 65537
n = p*q

def exgcd(x,y):
r0,r1 = x,y
a0,a1 = 1,0
b0,b1 = 0,1
while r1>0:
q1 = r0/r1
r2 = r0%r1
a2 = a0-q1*a1
b2 = b0-q1*b1
r0,r1 = r1,r2
a0,a1 = a1,a2
b0,b1 = b1,b2
return a0,b0,r0

d = exgcd(e,(p-1)*(q-1))[0] + (p-1)*(q-1)
exp1 = d % (p-1)
exp2 = d % (q-1)
coef = pow(q,p-2,p)

def int2bin(d):
t = "%x"%d
return (t if len(t)%2==0 else "0"+t).decode("hex")

def enclen(l):
if l<0x80:
return chr(l)
else:
t = int2bin(l)
return chr(0x80+len(t))+t

def encint(n):
t = int2bin(n)
return "\x02"+enclen(len(t))+t

t = "".join(map(encint,[0,n,e,d,p,q,exp1,exp2,coef]))
t = "\x30"+enclen(len(t))+t

print "-----BEGIN RSA PRIVATE KEY-----"
print t.encode("base64")[:-1]
print "-----END RSA PRIVATE KEY-----"
% genpriv.py > privkey.pem
% cat privkey.pem
-----BEGIN RSA PRIVATE KEY-----
MIGmAgEAAiC2Lc6fJYFjVyPbaxiPEvBGnL7gy8XayzbDbgyWtup7/QIDAQABAiBmFb0WyPl8JTRe
m+CjK8Wfmc4OQE8hvrvpfOO9bceNAQIQ0f2VZdriZPX9V5U9v7noDQIQ3hhDaCqytILM/1BvAs93
sQIQCdB3Rg5n3F4e3BQOkcJnlQIQP59HwBFrPBa0TvdltbJlIQIQcFyJhxTaQVkB9pJqKC2NOQ==
-----END RSA PRIVATE KEY-----

元メッセージをmessageとして保存しopensslでデコード処理。

% openssl enc -in message -out bintxt -d -a
% openssl rsautl -decrypt -in bintxt  -out plaintext -inkey privkey.pem
% cat plaintext
TMCTF{$@!zbo4+qt9=5}
  Analysis-offensive-200

apk解析系。apkstudioに食わせてsmailを読む問題と想定。手元に環境を用意していなかった(polictfでも似たような問題があったが別の端末で解いてた)ので、整備ツイデに並行してAndroid実機にapkをインストール。

なお、apkstidio付属のapktoolはそのままではエラーになるため、2.0.1に更新する必要がありました。

実機確認では1000000回ボタンをクリックしたらクリアになる単純なアプリの様子。

1000000の16進数表現 0x989680 で適当にファイルを探し、発見された \com\tm\ctf\clicker\activity\c.smali の中の該当数値だけを0x10に変えてビルド・インストール・実行。...動作が変わったように見えない。ここでしばらくはまる。

よくよくsmali関連のフォルダを見るとreceiverとか変なフォルダがありScoreBroadcastReveriver.smaliなどというファイルができていた。中を見るとc.smaliと似たような数値が書かれていること(grepの引数をサボって989680ではなく9896までにしたら98967fをたまたま発見)、および、元のc.smailにも0x989680に至るまでに何度か判定があるように見えた。ははーん両方同期して変えないとダメなのね。(このへん、アプリの構造をちゃんと読んでない適当思考である。プロセス間通信して相互チェックしてる、or片方はダミーでもう片方が有効とかなんでしょうが追いかけるのメンドウ)

const/16 v0, 0xeb9
const/16 v0, 0x2717
const v0, 0xe767
const v0, 0x186a3
const v0, 0x78e75
const v0, 0xf4243
const v0, 0x98967f

このへんを

const/16 v0, 0x2
const/16 v0, 0x4
const v0, 0x6
const v0, 0x8
const v0, 0xa
const v0, 0xc
const v0, 0xe

こんな感じに書き換えてアプリを起動。クリック16回くらいで終了。

TMCTF{Congrats_10MClicks}

 

なお、これらの手法をらくらく思いつけたのはSECCON 2015 橫浜大会の見学に行ったおかげです。紹介されたツールフル活用です。実機よりBlueStacksのほうが手間ないし。(とはいうもののCheatEngineは正直使いこなせず役に立ちませんでしたテヘ)

Analysis-defensive-100
% ./vonn
You are on VMM!
TMCTF{ce5d8bb4d5efe86d25098bec300d6954}

......え???w

Programming-100

あーこれって「iGame | 無料の目のテスト」これっすね。液晶スレでは有名です。ロボまで行ったウチの環境(EIZO L887&EV2334W)をなめるなー眼力勝負じゃー

 

...ごめん相手が悪かった。途中からpaint.netの助けも借りて42段階目までは行ったのだけど、さすがに小さすぎて色判別より先にクリック精度の限界w。

sed&awkで学びperl最強~な世代ではグラフィック処理なんてゼンゼン蚊帳の外だったので、write-up勢の書いてる「pythonで余裕っすw」とかから別次元に取り残された私は今回もbashImageMagickさんに頼るのでした。

% vi imgparse.sh
#!/bin/bash

starturl=http://ctfquest.trendmicro.co.jp:43210/click_on_the_different_color
base=http://ctfquest.trendmicro.co.jp:43210


function urlparse {
url=$1
#echo "parsing $url.."
next=$(curl -v $url | grep /img/ | sed -e 's,.*/,,' -e 's,\.png.*,,')
wget ${base}/img/${next}.png

color=$(convert ${next}.png -format %c histogram:info:- |grep -v white | sort -n|sed -e '/^$/d'|head -1 | awk -F# '{print $2}'| awk '{print $1}')

pos=$(convert ${next}.png txt:- | grep ${color} | head -1 | awk -F: '{print $1}')
x=$(echo $pos | awk -F, '{print $1}')
y=$(echo $pos | awk -F, '{print $2}')

newurl=$(printf "%s/%s?x=%d&y=%d" $base $next $x $y)
urlparse $newurl
}

urlparse $starturl

...いやImageMagickさん便利よ? まじで。convertコマンドはこんな感じでヒストグラム取れるし、各座標の値出したりできるのよ?

% convert 6c1c2686c14fcf0e815e37c57ece0282d43cfad7b.png -format %c histogram:info:-
35328: (122,125,121) #7A7D79 rgb(122,125,121)
16: (124,127,123) #7C7F7B rgb(124,127,123)
108297: (255,255,255) #FFFFFF white
% convert 4576c1c2686c14fcf0e815e37c57ece0282d43cfad7b.png txt:-
# ImageMagick pixel enumeration: 379,379,255,rgb
0,0: (255,255,255) #FFFFFF white
1,0: (255,255,255) #FFFFFF white
2,0: (255,255,255) #FFFFFF white
3,0: (255,255,255) #FFFFFF white
4,0: (255,255,255) #FFFFFF white
5,0: (255,255,255) #FFFFFF white
6,0: (255,255,255) #FFFFFF white
7,0: (255,255,255) #FFFFFF white
:
196,29: (122,125,121)  #7A7D79  rgb(122,125,121)
:

上のスクリプトではこのへんをこまめに処理してがんばりました。

というわけでローカルにフォルダにゴミを巻散らかしつつ最後まで行ってエラーになりはじめたら、最後に正解したっぽいURLをブラウザでアクセスしてフラグゲット。ごめん汚い処理で。

Congraturations!! The flag is TMCTF{U must have R0807 3Y3s!}

Cryptography-500

納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない納得いかない

Base64は「Base64 - Wikipedia」にあるように3バイト(×8ビット)を4バイト(×6ビット)に落とし込む変換なので、3バイトまでのアルファベット全てを変換し、条件に合ってしまうものを抽出し、全Base64文字列との差分を取れば終了、のはず。なので

% vi enc.pl   # アルファベット全パターンを出力
#!/usr/bin/perl

#@list = ('AAAA' .. 'ZZZZ');
@list = ('AAA' .. 'ZZZ');

foreach $a (@list){
my $b = lc $a;
my ($a1,$a2,$a3) = split //, $a;
my ($b1,$b2,$b3) = split //, $b;

printf "%s\n", $a1;
printf "%s\n", $b1;

printf "%s%s\n", $a1,$a2;
printf "%s%s\n", $a1,$b2;
printf "%s%s\n", $b1,$a2;
printf "%s%s\n", $b1,$b2;

printf "%s%s%s\n", $a1,$a2,$a3;
printf "%s%s%s\n", $a1,$a2,$b3;
printf "%s%s%s\n", $a1,$b2,$a3;
printf "%s%s%s\n", $a1,$b2,$b3;
printf "%s%s%s\n", $b1,$a2,$a3;
printf "%s%s%s\n", $b1,$a2,$b3;
printf "%s%s%s\n", $b1,$b2,$a3;
printf "%s%s%s\n", $b1,$b2,$b3;
}
% vi b64.pl # 全パターンをbase64 encode
#!/usr/bin/perl
use MIME::Base64;

while(<>){
chomp;
printf "%s",encode_base64($_);
}
% vi sp.pl # スペース区切りに分割(ワンライナーでも書けるけど一応...)
#!/usr/bin/perl

while(<>){
print join " ", split //;
}
% enc.pl > raw
% b64.pl < raw > candidate
% head candidate
QQ==
QUE=
QUFB
QUFC
QUFD
% sp.pl < candidate > o1
% head o1
Q Q = =
Q U E =
Q U F B
Q U F C
Q U F D
% awk '{print $1}' < o1 |sort|uniq> 1 # 問題の条件に合ってしまうものを抽出
% awk '{print $2}' < o1 |sort|uniq> 2
% awk '{print $3}' < o1 |sort|uniq> 3
% awk '{print $4}' < o1 |sort|uniq> 4
% cat 1 2 3 4 | sort | uniq > used # 全てをマージ
% diff -u used b64candidate # base64文字列候補とdiff
@@ -1,3 +1,5 @@
++
+/
0
1
2
@@ -5,6 +7,7 @@
4
5
6
+7
8
9
=
@@ -39,6 +42,7 @@
c
d
e
+f
g
h
i
% echo -n +/7f | sha1 # +が付いてる文字列を拾ってsha1取得。bsdなのでsha1コマンド
67569763552b4e9b8ac950be0d25f446f8470c60

これをTMCTF{}の指定フォーマットでくくってエントリするが弾かれる。(9/27 2:22頃)

base64の亜種(「_」や「-」等も使うやつ)かと思い、試すもNG。翌朝は用事で参加できないのであきらめ。実質的タイムアップ。

 

...他の方のwrite-up調べたら、どうもこれで合ってるようなんですが...。なぜ...orz
こういうのは後処理でスコア修正されるのが普通と思っていただけに残念。

Analysis-defensive-200

x64_dbgで追っかけるとホスト名取得して処理判定があるみたい。手元マシンのホスト名変えるといろいろと運用上の支障が出るので、vmのマシンを用意してホスト名変更して追いかける。

http://ctfquest.trendmicro.co.jp:13106/126ac9f6149081eb0e97c2e939eaad52/top.html

とかいうURLにアクセスしていること、および下記のような文字列を得る。fiddlerやらstoneで違うところに飛ばしてみたりしましたが解には至らず。後で考えるとCookie値操作やら、いろいろ試してみる余地はあったとは思いますが、点数面からCrypto500を優先したため時間的に深追いはできませんでした。(愚痴愚痴ちくちく)

localhost|8888
ctfquest.trendmicro.co.jp|19400
127.0.0.1|12345
Cookie: g1v3m3k3y=%d
g1v3m3k3y=0

 

SECCON 2014 横浜大会 バイナリ組 write-up

SECCON 2014 横浜大会に参加してきました。 バイナリ後半組、4問目で予選通過。 決勝リーグで早々と振り落とされるかと思いきや、運良く決勝まで残れました。 決勝にて早押しクイズで敗退。

後半組 1問目(10.zip) - まだ解けていません

オークション負け。 見守る。 カセットビジョンテニス(縦横反転)で勝てばフラグが表示されるらしい。 挑戦者はその場でうさみみハリケーンをダウンロードして会場を沸かせてました。

オークション時間が切れ、挑戦開始。最近kusano_kさんの日記で知ったx64_dbgにて解析開始。 このツール、64bit対応しているのはいいのだけどまだ品質がこなれておらず、step/nextで追いかけ中 落ちることがままあり。今回もデバッガ内で追いかけ中、点数が入った後落ちる。うーむollydbgに戻すか。ん? 再発? って犯人はIsDebuggerPresentか!というのに気づいたところで時間切れ。弱いな俺。ジャンル間違った感ひしひし。

後半組 2問目(04.txt) - 負け
00201000 >/$ 55             PUSH EBP
00201001  |. 8BEC           MOV EBP,ESP
00201003  |. 57             PUSH EDI
00201004  |. 8B7D 08        MOV EDI,DWORD PTR SS:[EBP+8]
00201007  |. 85FF           TEST EDI,EDI
00201009  |. 7E 0D          JLE SHORT 00201018
0020100B  |. 83FF 02        CMP EDI,2
0020100E  |. 7F 08          JG SHORT 00201018
00201010  |. B8 01000000    MOV EAX,1
00201015  |. 5F             POP EDI
00201016  |. 5D             POP EBP
00201017  |. C3             RETN
00201018  |> 8D47 FE        LEA EAX,DWORD PTR DS:[EDI-2]
0020101B  |. 56             PUSH ESI
0020101C  |. 50             PUSH EAX
0020101D  |. E8 DEFFFFFF    CALL 00201000
00201022  |. 4F             DEC EDI
00201023  |. 57             PUSH EDI
00201024  |. 8BF0           MOV ESI,EAX
00201026  |. E8 D5FFFFFF    CALL 00201000
0020102B  |. 83C4 08        ADD ESP,8
0020102E  |. 03C6           ADD EAX,ESI
00201030  |. 5E             POP ESI
00201031  |. 5F             POP EDI
00201032  |. 5D             POP EBP
00201033  \. C3             RETN
00201034     CC             INT3
00201040 >/$ 6A 2E          PUSH 2E
00201042  |. E8 B9FFFFFF    CALL 00201000
00201047  |. 6A 2D          PUSH 2D
00201049  |. 8BC8           MOV ECX,EAX
0020104B  |. E8 B0FFFFFF    CALL 00201000
00201050  |. 03C8           ADD ECX,EAX
00201052  |. 51             PUSH ECX
00201053  |. 68 F4202000    PUSH OFFSET format = "Key: %lu"
00201058  |. FF15 A0202000  CALL DWORD PTR DS:[<&MSVCR100.printf>]
0020105E  |. 83C4 10        ADD ESP,10
00201061  |. 33C0           XOR EAX,EAX
00201063  \. C3             RETN

オークション負け。見守る。コード部分ブロック範囲指定、Immunity Debuggerに流し込んでいる模様。手慣れてるなあ。

オークション時間が切れ、挑戦開始。同じように真ん中のコード部分をブロック範囲指定、デバッガに流し込み。普通に先頭から実行しただけでは動かないので 後半部分から実行されるような位置になるよう調整。(エントリポイントが後半であるようなヒントも出てた) ジャンプ先が前半部分のアドレスよりも低いアドレスとなるようなので、そこから実際のコードまでを全部0x90(NOP)で つぶして実行。動くようになる。けどprintfのところで落ちる。あーprintfのアドレスを実際のアドレスに変えないと動かないなー、とか考えてしまい printfのアドレスを探そうとしている途中に回答されてしまい終了。落ち着いて考えるとprintf呼ぶ直前にブレークしてレジスタの中身みればいいだけじゃん…。実際は緊張してこんなもんです。

後半組 3問目(06.zip) - 負け

オークション負け。見守る。暗号化前のテキストを復元せよ。前で解いてる方がIDAに突っ込むとfreadの文字、0x40の文字が 見える。ファイルサイズも64バイト。64バイト=512ビットということでSHA-512逆算か?とか一瞬身構えてしまうが画面上にCrypto系の関数名は見当たらず、コードもそれほど長くない。出力も64バイト。なんだ単なるテーブル変換か、とあたりをつける。

オークション時間が切れ、挑戦開始。処理予想通り。早々にテーブルを見つけ出し、切り出して逆変換コードを作成している間に回答されてしまい終了。うーむ。この手の処理は普段だと「1からつくってもすぐ」みたいな感覚があるからわざわざ持ち歩かないけど、こういう時間争いの場面では必要なんだな。反省。

後半組 4問目(02.exe) - 勝ち

オークション勝利。とりあえず壁紙を単色に変えてから前に出て投影。時間がかかる計算処理になっているそうな。解析開始。 とりあえずollydbgに食わせると共に、VMwareUbuntuからfile、upx -d、hexdump -C、objdump -d、strings等により難読化されていない普通のPEバイナリであり、鍵はそのままでは見えないことを確認する。(前半戦でupxされてた問題があった)

00E71000  /$ 53             PUSH EBX
00E71001  |. 56             PUSH ESI
00E71002  |. 57             PUSH EDI
00E71003  |. BE 01000000    MOV ESI,1
00E71008  |. 33DB           XOR EBX,EBX
00E7100A  |. 8D9B 00000000  LEA EBX,DWORD PTR DS:[EBX]
00E71010  |> 33FF           /XOR EDI,EDI
00E71012  |. 8D4F 01        |LEA ECX,DWORD PTR DS:[EDI+1]
00E71015  |. 3BF1           |CMP ESI,ECX
00E71017  |. 7C 1C          |JL SHORT 02.00E71035
00E71019  |. 8DA424 0000000>|LEA ESP,DWORD PTR SS:[ESP]
00E71020  |> 8BC6           |/MOV EAX,ESI
00E71022  |. 99             ||CDQ
00E71023  |. F7F9           ||IDIV ECX
00E71025  |. 85D2           ||TEST EDX,EDX
00E71027  |. 75 01          ||JNZ SHORT 02.00E7102A
00E71029  |. 47             ||INC EDI
00E7102A  |> 41             ||INC ECX
00E7102B  |. 3BCE           ||CMP ECX,ESI
00E7102D  |.^7E F1          |\JLE SHORT 02.00E71020
00E7102F  |. 83FF 02        |CMP EDI,2
00E71032  |. 75 01          |JNZ SHORT 02.00E71035
00E71034  |. 43             |INC EBX
00E71035  |> 46             |INC ESI
00E71036     81FB 80969800  |CMP EBX,989680
00E7103C  |.^7C D2          \JL SHORT 02.00E71010
00E7103E  |. 4E             DEC ESI
00E7103F  |. 56             PUSH ESI                                 ; /<%d>
00E71040  |. 68 F420E700    PUSH 02.00E720F4                         ; |format = "Key: %d"
00E71045  |. FF15 A420E700  CALL DWORD PTR DS:[<&MSVCR100.printf>]   ; \printf
00E7104B  |. 83C4 08        ADD ESP,8
00E7104E  |. FF15 9C20E700  CALL DWORD PTR DS:[<&MSVCR100.getchar>]  ; [getchar
00E71054  |. 5F             POP EDI
00E71055  |. 5E             POP ESI
00E71056  |. 33C0           XOR EAX,EAX
00E71058  |. 5B             POP EBX
00E71059  \. C3             RETN

該当処理は上のような感じ。どう見ても二重ループなので確かに遅そう。緊張してるのでCDQとかIDIVとか意味ど忘れ(超弱い)。とりあえずF8を押しっぱなしにしてレジスタの変化を見守る。処理の加速度的な落ち方を見て素数判定系とピンとくる。終了条件は0x989680、関数電卓に突っ込むと10,000,000(ゼロ7個)。

10,000,000以下の最大素数? と早とちりして回答を試み誤答。思考停止。ふたたびF8押しっぱなしとかして気を落ち着かせる。

数がでかいから遅い系の処理なのであれば、終了条件の数値が小さければ答えが出るのでは?と思いつき、バイナリエディタで0x989690(10,000,000)を0x03E8(1000)に書き換えたもの・0x2710(10000)に書き換えたもの処理をすることを思いつく。前者が数秒で答えが出る。7919。後者の答えは出ない。

スマホgoogle先生に聞くことにする。「1000 7919」で検索し「1000番目の素数」という文章を得る。これだ!と思い10,000,000番目の素数google先生に聞く。しかしそのものズバリの回答は得られず、近似方法とかアルゴリズムとかしか出てこない。焦っているのでタイプミス(ゼロの数間違う)とかもする。回答でてきた。179424673。そうこうしているうちに出題者からヒントが出始める。「これは実は素数の…」。うーわー。もうわかってるのにーやめてーーー

ヒント読み上げ中にノートへの回答転記が終わり、挙手して回答。正答。字汚くてスミマセンでした。

後半組 5問目(00.zip) - 配布無し、回答せず

サービス問題らしい。前に出た人が回答しちゃったので問題は取得できていません。コマンドラインに引数指定して実行するとkeyが出る系の何か。というか放心状態だったのでよく覚えていません。