KOSENセキュリティコンテスト2019 Writeup
この記事はKOSENセキュリティコンテスト2019 Writeup - Qiitaから移転してきたものです.
はじめに
10/26に開催されたKOSENセキュリティコンテスト2019に出場してきた.今年で3回目.
今年は例年と違って1日のみの6時間と大幅短い時間での開催になった.
結果は1160点で16位.もう少し頑張れた気もするけど,まぁこれが今の実力かなぁとも思った.
もっと精進せねば...
Writeup

問題が即削除されたのでかなり曖昧です...
運営さんはあれだけWriteupを書くことを推奨していたんだから問題を残しておいて(切実
とりあえず,.zsh_historyと記憶を頼りに解いた順に書いてく.
09 プログラミング言語を当てよう
早速,詰まった.いろいろ試したがヒットしないし,その割りに解答率がいいので話題のアレかとなった.(確か,returnを使った特徴的な記法で気がついた気がする.)
function inc(num)
num = num + 1
return num
class ClassName(name)
@name = name
@function output()
print("Hello, ")
print(self.name)
return
この言語の名前はBlawnなので問題文の通り(確かそう),大文字で
CTFKIT{BLAWN}17 目に見えなくても
問題に書いてあるリンクを踏むと何もかかれていないページが.
ページのソースを見るとflagが書いてある.

CTFKIT{html_may_be_including_hidden_text}12 大人たちの無意味な慣習
pcap問題.
とりあえずhtmlとcssとzipがあったのでエクスポート.

適当にhtmlを眺めてみると,

なんてこったい.
さっきエクスポートしたzipファイルにこのパスワードを突っ込んで解凍すると,
CTFKIT{majide_muimina_shuukan_dayonee}
##06 無言のELF
バイナリ問題.
実行すると無言で文字列の受付けをする.手がかりはなし.
gdb-pedaに投げる.
アセンブラ全文
gdb-peda$ pdisass
Dump of assembler code for function main:
0x000055555555480a <+0>: push rbp
0x000055555555480b <+1>: mov rbp,rsp
0x000055555555480e <+4>: push r15
0x0000555555554810 <+6>: push r14
0x0000555555554812 <+8>: push r13
0x0000555555554814 <+10>: push r12
0x0000555555554816 <+12>: push rbx
0x0000555555554817 <+13>: sub rsp,0x168
0x000055555555481e <+20>: mov rax,QWORD PTR fs:0x28
0x0000555555554827 <+29>: mov QWORD PTR [rbp-0x38],rax
0x000055555555482b <+33>: xor eax,eax
0x000055555555482d <+35>: movabs rax,0x676665646362615f
0x0000555555554837 <+45>: movabs rdx,0x6f6e6d6c6b6a6968
0x0000555555554841 <+55>: mov QWORD PTR [rbp-0x170],rax
0x0000555555554848 <+62>: mov QWORD PTR [rbp-0x168],rdx
0x000055555555484f <+69>: movabs rax,0x7776757473727170
0x0000555555554859 <+79>: movabs rdx,0x34333231307a7978
0x0000555555554863 <+89>: mov QWORD PTR [rbp-0x160],rax
0x000055555555486a <+96>: mov QWORD PTR [rbp-0x158],rdx
0x0000555555554871 <+103>: mov DWORD PTR [rbp-0x150],0x38373635
0x000055555555487b <+113>: mov WORD PTR [rbp-0x14c],0x39
0x0000555555554884 <+122>: mov rdx,QWORD PTR [rip+0x200785] # 0x555555755010 <stdin@@GLIBC_2.2.5>
0x000055555555488b <+129>: lea rax,[rbp-0x140]
0x0000555555554892 <+136>: mov esi,0x100
0x0000555555554897 <+141>: mov rdi,rax
0x000055555555489a <+144>: call 0x5555555546c0 <fgets@plt>
0x000055555555489f <+149>: lea rax,[rbp-0x140]
0x00005555555548a6 <+156>: lea rsi,[rip+0x22b] # 0x555555554ad8
0x00005555555548ad <+163>: mov rdi,rax
0x00005555555548b0 <+166>: call 0x5555555546e0 <strtok@plt>
0x00005555555548b5 <+171>: lea rax,[rbp-0x140]
0x00005555555548bc <+178>: lea rsi,[rip+0x217] # 0x555555554ada
0x00005555555548c3 <+185>: mov rdi,rax
0x00005555555548c6 <+188>: call 0x5555555546d0 <strcmp@plt>
0x00005555555548cb <+193>: test eax,eax
0x00005555555548cd <+195>: jne 0x555555554a0e <main+516>
0x00005555555548d3 <+201>: movzx eax,BYTE PTR [rbp-0x161]
0x00005555555548da <+208>: movsx esi,al
0x00005555555548dd <+211>: movzx eax,BYTE PTR [rbp-0x150]
0x00005555555548e4 <+218>: movsx edi,al
0x00005555555548e7 <+221>: movzx eax,BYTE PTR [rbp-0x15c]
0x00005555555548ee <+228>: movsx r8d,al
0x00005555555548f2 <+232>: movzx eax,BYTE PTR [rbp-0x16b]
0x00005555555548f9 <+239>: movsx r9d,al
0x00005555555548fd <+243>: movzx eax,BYTE PTR [rbp-0x168]
0x0000555555554904 <+250>: movsx eax,al
0x0000555555554907 <+253>: mov DWORD PTR [rbp-0x174],eax
0x000055555555490d <+259>: movzx eax,BYTE PTR [rbp-0x160]
0x0000555555554914 <+266>: movsx ebx,al
0x0000555555554917 <+269>: mov DWORD PTR [rbp-0x178],ebx
0x000055555555491d <+275>: movzx eax,BYTE PTR [rbp-0x152]
0x0000555555554924 <+282>: movsx ecx,al
0x0000555555554927 <+285>: mov DWORD PTR [rbp-0x17c],ecx
0x000055555555492d <+291>: movzx eax,BYTE PTR [rbp-0x15c]
0x0000555555554934 <+298>: movsx edx,al
0x0000555555554937 <+301>: mov DWORD PTR [rbp-0x180],edx
0x000055555555493d <+307>: movzx eax,BYTE PTR [rbp-0x16b]
0x0000555555554944 <+314>: movsx r15d,al
0x0000555555554948 <+318>: movzx eax,BYTE PTR [rbp-0x170]
0x000055555555494f <+325>: movsx r14d,al
0x0000555555554953 <+329>: movzx eax,BYTE PTR [rbp-0x15e]
0x000055555555495a <+336>: movsx r13d,al
0x000055555555495e <+340>: movzx eax,BYTE PTR [rbp-0x16e]
0x0000555555554965 <+347>: movsx r12d,al
0x0000555555554969 <+351>: movzx eax,BYTE PTR [rbp-0x168]
0x0000555555554970 <+358>: movsx ebx,al
0x0000555555554973 <+361>: movzx eax,BYTE PTR [rbp-0x160]
0x000055555555497a <+368>: movsx r11d,al
0x000055555555497e <+372>: movzx eax,BYTE PTR [rbp-0x167]
0x0000555555554985 <+379>: movsx r10d,al
0x0000555555554989 <+383>: mov DWORD PTR [rbp-0x184],r10d
0x0000555555554990 <+390>: movzx eax,BYTE PTR [rbp-0x150]
0x0000555555554997 <+397>: movsx r10d,al
0x000055555555499b <+401>: movzx eax,BYTE PTR [rbp-0x16e]
0x00005555555549a2 <+408>: movsx ecx,al
0x00005555555549a5 <+411>: movzx eax,BYTE PTR [rbp-0x160]
0x00005555555549ac <+418>: movsx edx,al
0x00005555555549af <+421>: movzx eax,BYTE PTR [rbp-0x168]
0x00005555555549b6 <+428>: movsx eax,al
0x00005555555549b9 <+431>: push rsi
0x00005555555549ba <+432>: push rdi
0x00005555555549bb <+433>: push r8
0x00005555555549bd <+435>: push r9
0x00005555555549bf <+437>: mov esi,DWORD PTR [rbp-0x174]
0x00005555555549c5 <+443>: push rsi
0x00005555555549c6 <+444>: mov edi,DWORD PTR [rbp-0x178]
0x00005555555549cc <+450>: push rdi
0x00005555555549cd <+451>: mov esi,DWORD PTR [rbp-0x17c]
0x00005555555549d3 <+457>: push rsi
0x00005555555549d4 <+458>: mov edi,DWORD PTR [rbp-0x180]
0x00005555555549da <+464>: push rdi
0x00005555555549db <+465>: push r15
0x00005555555549dd <+467>: push r14
0x00005555555549df <+469>: push r13
0x00005555555549e1 <+471>: push r12
0x00005555555549e3 <+473>: push rbx
0x00005555555549e4 <+474>: push r11
0x00005555555549e6 <+476>: mov r9d,DWORD PTR [rbp-0x184]
0x00005555555549ed <+483>: mov r8d,r10d
0x00005555555549f0 <+486>: mov esi,eax
0x00005555555549f2 <+488>: lea rdi,[rip+0xff] # 0x555555554af8
0x00005555555549f9 <+495>: mov eax,0x0
0x00005555555549fe <+500>: call 0x5555555546b0 <printf@plt>
=> 0x0000555555554a03 <+505>: add rsp,0x70
0x0000555555554a07 <+509>: mov eax,0x0
0x0000555555554a0c <+514>: jmp 0x555555554a1f <main+533>
0x0000555555554a0e <+516>: lea rdi,[rip+0x113] # 0x555555554b28
0x0000555555554a15 <+523>: call 0x555555554690 <puts@plt>
0x0000555555554a1a <+528>: mov eax,0x1
0x0000555555554a1f <+533>: mov rbx,QWORD PTR [rbp-0x38]
0x0000555555554a23 <+537>: xor rbx,QWORD PTR fs:0x28
0x0000555555554a2c <+546>: je 0x555555554a33 <main+553>
0x0000555555554a2e <+548>: call 0x5555555546a0 <__stack_chk_fail@plt>
0x0000555555554a33 <+553>: lea rsp,[rbp-0x28]
0x0000555555554a37 <+557>: pop rbx
0x0000555555554a38 <+558>: pop r12
0x0000555555554a3a <+560>: pop r13
0x0000555555554a3c <+562>: pop r14
0x0000555555554a3e <+564>: pop r15
0x0000555555554a40 <+566>: pop rbp
0x0000555555554a41 <+567>: ret
End of assembler dump.gdb-peda$ start
適当にnextを押していたら終わってしまった.
しかし,途中でstrcompとjneの分岐があった.非常に怪しい.
ここをうまく分岐の中に入れればいい感じなんじゃないか?
そこでjne命令のところでflag(レジスタの方)を書き換える.
gdb-peda$ info registers eflags
eflags 0x282 [ SF IF ]
gdb-peda$ set $eflags ^= (1 << 6)
gdb-peda$ info registers eflags
eflags 0x2c2 [ ZF SF IF ]
ゼロフラグを書き換えた.これでジャンプしないはず.
ジャンプしないまま続けるとレジスタにそれっぽい文字列が出てき始める.

しばらくまたnextで進めていくとprintfにぶつかりflagが出力される.
CTFKIT{hpb5iphbr_et3phet5o}
gdbだと出力がすぐに次に行っちゃって分かり辛いので注意.
02 伝統的な暗号
確かキーの長さが三文字と問題文に書いてあった.
換字式暗号であることは間違いないが,3文字って何...?
結構時間がかかった問題.
与えられた文字列:UAPCPD{vv_e_cuyo_csylxwyo_upzzlb?}
とりあえず,CTFKITの文字は確定してるのでCとU,TとA,FとP...と六文字の文字の距離を測ってみる.
def dist(y,x):
counter=0
x=ord(x.lower())
y=ord(y.lower())
while(True):
if(x==y):
return counter
y+=1
#print(chr(y))
counter+=1
if(y==ord('z')+1):
y=ord('a')
given="UAPCPD{vv_e_cuyo_csylxwyo_upzzlb?}"
flag_format="CTFKIT"
for i in range(len(flag_format)):
print(dist(given[i],flag_format[i]),end=" ")
print()
すると,
8 19 16 8 19 16
周期的な並びが出てくる.
つまり,8個ずらす,19個ずらす,16個ずらす...を繰り替えしているっぽい.
これを与えられた文字列すべてにやれば大丈夫そう.
ただし,記号は例外なので除外しておく.
def shift(x,y):
x=x.lower()
ret=ord(x)+y
if(ret>ord('z')):
ret=ord('a')+(ret-ord('z')-1)
return chr(ret)
def decrypt(given):
counter=0
for i in (range(len(given))):
if(ord(given[i])>ord('a') and (given[i] != '{' and given[i] != '}' and given[i] != '_' )):
if(counter%3==0):
print(shift(given[i],8),end="")
elif(counter%3==1):
print(shift(given[i],19),end="")
elif(counter%3==2):
print(shift(given[i],16),end="")
counter+=1
else:
print(given[i],end="")
given="UAPCPD{vv_e_cuyo_csylxwyo_upzzlb?}"
flag_format="CTFKIT"
print(flag_format,end="")
decrypt(given[6:])
print()CTFKIT{do_u_know_vigenere_cipher?}
どうやらヴィジュネル暗号というらしい.
14 お茶をさぐれ
友達から急に解き途中のプログラムが渡されて訳も分からず解いた.
一応途中からだけど書き残す.
といっても多分もう終盤.apkのファイルまで抽出できているのでこれを好きな言語で書き直して実行するだけ.
もらったapk
live:yuhma5 ,12:37
package com.example.ureshino.ctfmondai_android;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class LoginActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private static final String[] DUMMY_CREDENTIALS = { "[email protected]:tenaoyhr" };
private static final int REQUEST_READ_CONTACTS = 0;
private UserLoginTask mAuthTask = null;
private AutoCompleteTextView mEmailView;
private View mLoginFormView;
private EditText mPasswordView;
private View mProgressView;
private boolean LoginTask(String paramString1, String paramString2) {
String[] arrayOfString = DUMMY_CREDENTIALS;
int i = arrayOfString.length;
boolean bool = false;
for (byte b = 0; b < i; b++) {
String[] arrayOfString1 = nyaho(arrayOfString[b]).split(":");
if (arrayOfString1[0].equals(paramString1))
bool = arrayOfString1[1].equals(paramString2);
}
return bool;
}
private void addEmailsToAutoComplete(List<String> paramList) {
ArrayAdapter arrayAdapter = new ArrayAdapter(this, 17367050, paramList);
this.mEmailView.setAdapter(arrayAdapter);
}
private void attemptLogin() {
if (this.mAuthTask != null)
return;
this.mEmailView.setError(null);
this.mPasswordView.setError(null);
String str1 = this.mEmailView.getText().toString();
String str2 = this.mPasswordView.getText().toString();
byte b2 = 0;
StringBuilder stringBuilder = null;
byte b1 = b2;
AutoCompleteTextView autoCompleteTextView = stringBuilder;
if (!TextUtils.isEmpty(str2)) {
b1 = b2;
autoCompleteTextView = stringBuilder;
if (!isPasswordValid(str2)) {
this.mPasswordView.setError(getString(2131558449));
autoCompleteTextView = this.mPasswordView;
b1 = 1;
}
}
if (TextUtils.isEmpty(str1)) {
this.mEmailView.setError(getString(2131558446));
AutoCompleteTextView autoCompleteTextView1 = this.mEmailView;
b1 = 1;
} else if (!isEmailValid(str1)) {
this.mEmailView.setError(getString(2131558448));
autoCompleteTextView = this.mEmailView;
b1 = 1;
}
if (b1 != 0) {
autoCompleteTextView.requestFocus();
return;
}
if (LoginTask(str1, str2)) {
TextView textView = (TextView)findViewById(2131230792);
textView.setVisibility(0);
stringBuilder = new StringBuilder();
stringBuilder.append(f());
stringBuilder.append(l());
stringBuilder.append(o());
stringBuilder.append(g());
stringBuilder.append(g2());
stringBuilder.append(e());
stringBuilder.append(h());
stringBuilder.append(i());
stringBuilder.append(j());
stringBuilder.append(k());
stringBuilder.append(l2());
stringBuilder.append(n());
stringBuilder.append(o2());
String str = stringBuilder.toString();
StringBuilder stringBuilder1 = new StringBuilder();
stringBuilder1.append("CTFKIT{");
stringBuilder1.append(nyaho(str));
stringBuilder1.append("}");
textView.setText(stringBuilder1.toString());
return;
}
this.mEmailView.setError("Login Failed.... ((((((((((っ・ω・)っ ");
((TextView)findViewById(2131230792)).setVisibility(4);
this.mEmailView.requestFocus();
}
private boolean isEmailValid(String paramString) { return paramString.contains("@"); }
private boolean isPasswordValid(String paramString) { return (paramString.length() > 4); }
private boolean mayRequestContacts() {
if (Build.VERSION.SDK_INT < 23)
return true;
if (checkSelfPermission("android.permission.READ_CONTACTS") == 0)
return true;
if (shouldShowRequestPermissionRationale("android.permission.READ_CONTACTS")) {
Snackbar.make(this.mEmailView, 2131558459, -2).setAction(17039370, new View.OnClickListener() {
@TargetApi(23)
public void onClick(View param1View) { LoginActivity.this.requestPermissions(new String[] { "android.permission.READ_CONTACTS" }, 0); }
});
return false;
}
requestPermissions(new String[] { "android.permission.READ_CONTACTS" }, 0);
return false;
}
private void populateAutoComplete() {
if (!mayRequestContacts())
return;
getLoaderManager().initLoader(0, null, this);
}
@TargetApi(13)
private void showProgress(final boolean show) {
int i = Build.VERSION.SDK_INT;
int k = 0;
int j = 0;
if (i >= 13) {
float f1;
k = getResources().getInteger(17694720);
View view2 = this.mLoginFormView;
if (paramBoolean) {
i = 8;
} else {
i = 0;
}
view2.setVisibility(i);
ViewPropertyAnimator viewPropertyAnimator2 = this.mLoginFormView.animate().setDuration(k);
float f2 = 1.0F;
if (paramBoolean) {
f1 = 0.0F;
} else {
f1 = 1.0F;
}
viewPropertyAnimator2.alpha(f1).setListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator param1Animator) {
byte b;
View view = LoginActivity.this.mLoginFormView;
if (show) {
b = 8;
} else {
b = 0;
}
view.setVisibility(b);
}
});
View view1 = this.mProgressView;
if (paramBoolean) {
i = j;
} else {
i = 8;
}
view1.setVisibility(i);
ViewPropertyAnimator viewPropertyAnimator1 = this.mProgressView.animate().setDuration(k);
if (paramBoolean) {
f1 = f2;
} else {
f1 = 0.0F;
}
viewPropertyAnimator1.alpha(f1).setListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator param1Animator) {
byte b;
View view = LoginActivity.this.mProgressView;
if (show) {
b = 0;
} else {
b = 8;
}
view.setVisibility(b);
}
});
return;
}
View view = this.mProgressView;
if (paramBoolean) {
i = 0;
} else {
i = 8;
}
view.setVisibility(i);
view = this.mLoginFormView;
i = k;
if (paramBoolean)
i = 8;
view.setVisibility(i);
}
public String e() { return "v"; }
public String f() { return "h"; }
public String g() { return "f"; }
public String g2() { return "u"; }
public String h() { return "a"; }
public String i() { return "b"; }
public String j() { return "_"; }
public String k() { return "g"; }
public String l() { return "e"; }
public String l2() { return "r"; }
public String n() { return "n"; }
public String nyaho(String paramString) {
char[] arrayOfChar = new char[paramString.length()];
byte b;
for (b = 0; b < paramString.length(); b++) {
char c;
char c1 = paramString.charAt(b);
if (c1 >= 'a' && c1 <= 'm') {
c = (char)(c1 + '\r');
} else if (c1 >= 'A' && c1 <= 'M') {
c = (char)(c1 + '\r');
} else if (c1 >= 'n' && c1 <= 'z') {
c = (char)(c1 - '\r');
} else {
c = c1;
if (c1 >= 'N') {
c = c1;
if (c1 <= 'Z')
c = (char)(c1 - '\r');
}
}
arrayOfChar[b] = c;
}
return String.valueOf(arrayOfChar);
}
public String o() { return "r"; }
public String o2() { return "_"; }
protected void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
setContentView(2131427356);
this.mEmailView = (AutoCompleteTextView)findViewById(2131230778);
populateAutoComplete();
this.mPasswordView = (EditText)findViewById(2131230832);
this.mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView param1TextView, int param1Int, KeyEvent param1KeyEvent) {
if (param1Int == 6 || param1Int == 0) {
LoginActivity.this.attemptLogin();
return true;
}
return false;
}
});
((Button)findViewById(2131230780)).setOnClickListener(new View.OnClickListener() {
public void onClick(View param1View) { LoginActivity.this.attemptLogin(); }
});
this.mLoginFormView = findViewById(2131230812);
this.mProgressView = findViewById(2131230813);
}
public Loader<Cursor> onCreateLoader(int paramInt, Bundle paramBundle) { return new CursorLoader(this, Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI, "data"), ProfileQuery.PROJECTION, "mimetype = ?", new String[] { "vnd.android.cursor.item/email_v2" }, "is_primary DESC"); }
public void onLoadFinished(Loader<Cursor> paramLoader, Cursor paramCursor) {
ArrayList arrayList = new ArrayList();
paramCursor.moveToFirst();
while (!paramCursor.isAfterLast()) {
arrayList.add(paramCursor.getString(0));
paramCursor.moveToNext();
}
addEmailsToAutoComplete(arrayList);
}
public void onLoaderReset(Loader<Cursor> paramLoader) {}
public void onRequestPermissionsResult(int paramInt, @NonNull String[] paramArrayOfString, @NonNull int[] paramArrayOfInt) {
if (paramInt == 0 && paramArrayOfInt.length == 1 && paramArrayOfInt[0] == 0)
populateAutoComplete();
}
private static interface ProfileQuery {
public static final int ADDRESS = 0;
public static final int IS_PRIMARY = 1;
public static final String[] PROJECTION = { "data1", "is_primary" };
}
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
private final String mEmail;
private final String mPassword;
UserLoginTask(String param1String1, String param1String2) {
this.mEmail = param1String1;
this.mPassword = param1String2;
}
protected Boolean doInBackground(Void... param1VarArgs) {
try {
Thread.sleep(100L);
String[] arrayOfString = DUMMY_CREDENTIALS;
int i = arrayOfString.length;
for (byte b = 0; b < i; b++) {
String[] arrayOfString1 = arrayOfString[b].split(":");
if (arrayOfString1[0].equals(this.mEmail))
arrayOfString1[1].equals(this.mPassword);
}
return Boolean.valueOf(true);
} catch (InterruptedException param1VarArgs) {
return Boolean.valueOf(false);
}
}
protected void onCancelled() {
LoginActivity.access$402(LoginActivity.this, null);
LoginActivity.this.showProgress(false);
}
protected void onPostExecute(Boolean param1Boolean) {
LoginActivity.access$402(LoginActivity.this, null);
LoginActivity.this.showProgress(false);
if (param1Boolean.booleanValue()) {
LoginActivity.this.finish();
return;
}
LoginActivity.this.mPasswordView.setError(LoginActivity.this.getString(2131558447));
LoginActivity.this.mPasswordView.requestFocus();
}
}
}どう考えてもここが怪しい.
stringBuilder = new StringBuilder();
stringBuilder.append(f());
stringBuilder.append(l());
stringBuilder.append(o());
stringBuilder.append(g());
stringBuilder.append(g2());
stringBuilder.append(e());
stringBuilder.append(h());
stringBuilder.append(i());
stringBuilder.append(j());
stringBuilder.append(k());
stringBuilder.append(l2());
stringBuilder.append(n());
stringBuilder.append(o2());
String str = stringBuilder.toString();
StringBuilder stringBuilder1 = new StringBuilder();
stringBuilder1.append("CTFKIT{");
stringBuilder1.append(nyaho(str));
stringBuilder1.append("}");
適当な関数から文字列をもらってそれを結合,それをさらにnyahoという関数にかけてflag化してる.
public String e() { return "v"; }
public String f() { return "h"; }
public String g() { return "f"; }
public String g2() { return "u"; }
public String h() { return "a"; }
public String i() { return "b"; }
public String j() { return "_"; }
public String k() { return "g"; }
public String l() { return "e"; }
public String l2() { return "r"; }
public String n() { return "n"; }
public String nyaho(String paramString) {
char[] arrayOfChar = new char[paramString.length()];
byte b;
for (b = 0; b < paramString.length(); b++) {
char c;
char c1 = paramString.charAt(b);
if (c1 >= 'a' && c1 <= 'm') {
c = (char)(c1 + '\r');
} else if (c1 >= 'A' && c1 <= 'M') {
c = (char)(c1 + '\r');
} else if (c1 >= 'n' && c1 <= 'z') {
c = (char)(c1 - '\r');
} else {
c = c1;
if (c1 >= 'N') {
c = c1;
if (c1 <= 'Z')
c = (char)(c1 - '\r');
}
}
arrayOfChar[b] = c;
}
return String.valueOf(arrayOfChar);
}
必要な情報はすべてもらったソースコードにあるのでpythonに書き換えて復号していく.
まず,nyahoに与えられる文字列strだが,これは気合で集めた.(は?
あとはnyahoを以下のスクリプトに書き直せば完成.
def decrypt(given):
counter=0
for i in (range(len(given))):
c=ord(given[i])
if(c >= ord('a') and c <= ord('m')):
print(chr(c+ord('\r')),end="")
elif(c >= ord('A') and c <= ord('M')):
print(chr(c+ord('\r')),end="")
elif(c >= ord('n') and c <= ord('z')):
print(chr(c-ord('\r')),end="")
else:
if(c>=ord('N')):
if(c<=ord('Z')):
print(chr(c-ord('\r')),end="")
else:
print(chr(c),end="")
else:
print(chr(c),end="")
given="herfuvab_grn_"
print("CTFKIT{",end="")
decrypt(given)
print("}")CTFKIT{ureshino_tea_}13 名前を解決したい
DNSの問題.もうサーバは動いてないので記憶と記録頼り.
DNSの設定ミスで名前解決ができなくて与えられたリンクにアクセスできない.
与えられたURL:http://futuregadget-9.tech
とりあえず,digをうって確認.
$ dig http://futuregadget-9.tech
; <<>> DiG 9.11.5-P4-1-Debian <<>> http://futuregadget-9.tech
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 61541
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;http://futuregadget-9.tech. IN A
;; AUTHORITY SECTION:
tech. 3600 IN SOA ns0.centralnic.net. hostmaster.centralnic.net. 262197 900 1800 6048000 3600
;; Query time: 99 msec
;; SERVER: 192.168.0.1#53(192.168.0.1)
;; WHEN: 月 11月 04 23:06:27 JST 2019
;; MSG SIZE rcvd: 120
有力な情報は見つからない.
あれこれオプションを試してみるが芳しくない.
(後で他の人のwriteupを見たらこれでいけていた.何で?(殺意))
自分の場合は以下でうまくいった.
dig http://futuregadget-9.tech -p80
textにIPがあることは分かっていたのになぁ...
なんでダメだったんだろう.
IPが出てくるのでそこにアクセスする.

CTFKIT{naki_nureshi_megami_no_kikan}20 偉くなりたい
自分が閃いて解いたのだが,肝心のhtmlが無いので解説できない.
見つかり次第追記するが,htmlのhidden属性のフォームが隠されていてそのフォームの属性をtextに変えてその欄にデフォルトでかかれているis_not_adminをis_adminに変えて送信するとflagが落ちてくる仕組み.
自分でもよく閃いたと思う.
10 ツートントン
割とよくあるモールス問題.
以下のような画像が与えられる.

小さいので拡大するとこう.(これがまずかった.)

どうやらこれがモールスの並びっぽい.
画像のピクセルを読んでビットに置き換える.
ところが,さっき拡大してしまったのでどこのピクセルの値を取るかで迷ってしまった.
ここでかなり時間を取られた.実は,親切にも最初の画像が1ドット1ピクセルになってた.(友達に言われるまで気づかなかった)
とりあえず,ビットに起こす.
import cv2
img=cv2.imread("image.png")
h,w,c=img.shape
x=45
y=45
print(h,w)
for i in range(x):
for j in range(y):
if(img[i,j][0]):
print("+",end="")
else:
print("-",end="")
print()45 45
+-----++++++--++--++--++--++++++--++--++++++-
-++--++--++++++++++++++--++--++++++--++--++--
++++++++++++++-----++-----++++++-----++-----+
+-----++++++--++-----++--++++++--++--++--++++
++--++++++++++++++-----++--++-----++--++++++-
----++-----++-----++++++-----++--++--++++++--
++++++--++-----++--++-----++--++-----++++++++
++++++-----++--++-----++--++++++--++-----++++
++-----++--++++++++++++++-----++--++-----++--
---++++++-----++-----++-----++++++--++--++---
--++++++++++++++--++--++-----++--++++++--++--
++++++-----++--++++++-----++--++--+++++++++++
+++-----++++++--++--++--++--++++++--+++++++++
+++++--++--++-----++--++++++--++-----++--++--
++++++--++-----++++++-----++-----++--++++++--
++--++-----++-----++--++--++++++++++++++-----
++++++--++--++--++--++++++--++++++++++++++--+
+--++-----++--++++++--++-----++--++--++++++--
++-----++++++-----++-----++--++++++++++++++--
++--++++++--++--++--++++++++++++++-----++--++
-----++--++++++-----++++++--++--++-----++--++
++++-----++--++-----++++++--++--++++++-----++
++++-----++--++-----++-----++--++++++-----+++
+++--++--++-----++++++--++--++-----++++++----
-++--++--++--++-----++++++-----++++++-----++-
----++-----++++++-----++--++++++-----++--++--
++--++-----++++++-----++++++-----++-----++---
--++++++-----++--++++++-----++--++--++--++---
--++++++-----++++++--++--++-----++++++--++--+
+-----++++++-----++--++--++--++-----++++++---
--++++++-----++-----++-----++++++-----++--+++
+++-----++--++-----++-----++--++-----++++++++
++++++--++--++--++--++++++--++-----++++++--++
--++--++--++++++--++-----++++++-----++-----++
--++--++-----++-----++++++++++++++-----++--++
-----++--++++++--++-----++++++-----++--++++++
++++++++-----++--++-----++-----++++++-----++-
----++-----++++++--++--++-----++++++++++++++-
-++--++-----++--++++++--++--++++++-----++--++
++++-----++--++--++++++++++++++--++--++++++--
---++++++--++--++-----++-----++--++--++++++++
+++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++
これをモールス信号に整形する.
短音がマイナス2つ,長音がマイナス5つ,単語の区切りがプラス6つなのを考慮して置換する.(よく考えたらプラスとマイナス逆だなぁ...
置換したものがこちらになります.
_ .... .. ... .. ... __ ___ ._. ... . _._. ___ _.. . ._._._ _._. ._ _. _.__ ___ .._ .._. .. _. _.. _ .... . .._. ._.. ._ __. ..__.. _ .... . .._. ._.. ._ __. .. ... _._. _ .._. _._ .. _ _.__. _ .._ .._ _..._ _ ___ _. _..._ _ ___ _. _..._ _ .._ .._ _..._ _ ___ _. _.__._ .... ._ .... ._ __..__ _._. ._ _. _.__ ___ .._ .._. .. _. _.. .. _ ..__..
後はこれをwebのツールに投げておしまい.

括弧は問題文の通り置換する.
CTFKIT{TUU=TON=TON=TUU=TON}感想
一週間も間が空いてしまったがコマンドの履歴とソルバとかファイルが残っていてぎりぎり書けた.
難しいだろうけど運営は問題をWriteup用にしばらく残して(切実
偉くなりたいは頼みのキャッシュにページが無かったので探し中.もし見つかったら追記する.
こうみると結構解いたなぁと思う.頑張った自分.
まだまだ実力と経験不足なのでこれからも精進したい.
追記
書いたデータが知らず知らずのうちに消えてた(全ギレ
投稿した矢先に編集してすいません.
睡眠時間を返して.