how to apt-get from the internal network: remote sshd with kneesocks
DESCRIPTION
2014/09/14 すみだセキュリティ勉強会2014#3TRANSCRIPT
HOW TO APT-GET FROM THE INTERNAL NETWORK
REMOTE SSHD WITH KNEESOCKS
2014/09/14
すみだセキュリティ勉強会2014#3
@inaz2
About me
• @inaz2
• Security engineer & Python programmer
• Girls Idol Freak
•ももいろテクノロジー
• http://inaz2.hatenablog.com/
2
ONE DAY
I wanted to apt-get from sv2
LAN: 192.168.0.0/24
Internal: 10.0.0.0/24
.1
.2
.2 .3
router
sv1 sv2
Internet
4
I wanted to apt-get from sv2
LAN: 192.168.0.0/24
Internal: 10.0.0.0/24
.1
.2
.2 .3
router
sv1 sv2
Internet
$ sudo apt-get updateErr http://security.ubuntu.com precise-security Release.gpg
Temporary failure resolving 'security.ubuntu.com'
5
THE NEXT DAY
I used HTTP Proxy
LAN: 192.168.0.0/24
Internal: 10.0.0.0/24
.1
.2
.2 .3
router
sv1 sv2HTTP Proxy
Internet
7
I used HTTP Proxy
LAN: 192.168.0.0/24
Internal: 10.0.0.0/24
.1
.2
.2 .3
router
sv1 sv2HTTP Proxy
Internet
$ sudo http_proxy=http://10.0.0.2:8080/ apt-get updateGet:1 http://jp.archive.ubuntu.com precise Release.gpg [198 B]
8
HTTP Proxy worked, but …
•別のマシンにProxyサーバを立てる必要がある
• http_proxy環境変数を読まないコマンドもある
• HTTP以外のプロトコルには使えない
9
HTTP Proxy worked, but …
•別のマシンにProxyサーバを立てる必要がある
• http_proxy環境変数を読まないコマンドもある
• HTTP以外のプロトコルには使えない
10
汎用性低い
OpenSSH Dynamic Port Forwarding
• ssh -D 1080 user@sv1
• localhost:1080 を指定することで、sv1をSOCKS Proxyとして使うことができる
• HTTPに限らず、あらゆるTCP/UDPプロトコルに使える
• OpenSSHはほとんどのサーバで動いている
11
OpenSSH Dynamic Port Forwarding
• ssh -D 1080 user@sv1
• localhost:1080 を指定することで、sv1をSOCKS Proxyとして使うことができる
• HTTPに限らず、あらゆるTCP/UDPプロトコルに使える
• OpenSSHはほとんどのサーバに入っている
汎用性高い12
SOCKSIFY(1)
• DanteというSOCKS Proxy実装に含まれるコマンド
• https://www.inet.no/dante/
• sudo apt-get install dante-client
•ライブラリ関数をフックすることで、任意のコマンドをSOCKS Proxyに対応させることができる
•このようなプログラムは Proxifierと呼ばれる
• http://en.wikipedia.org/wiki/Comparison_of_proxifiers
13
SOCKSIFY(1)
• DanteというSOCKS Proxy実装に含まれるコマンド
• https://www.inet.no/dante/
• sudo apt-get install dante-client
•ライブラリ関数をフックすることで、任意のコマンドをSOCKS Proxyに対応させることができる
•このようなプログラムは Proxifierと呼ばれる
• http://en.wikipedia.org/wiki/Comparison_of_proxifiers
$ SOCKS_PROXY=localhost:1080 socksify curl http://www.example.com/
14
SOCKSIFY(1)
• DanteというSOCKS Proxy実装に含まれるコマンド
• https://www.inet.no/dante/
• sudo apt-get install dante-client
•ライブラリ関数をフックすることで、任意のコマンドをSOCKS Proxyに対応させることができる
•このようなプログラムは Proxifierと呼ばれる
• http://en.wikipedia.org/wiki/Comparison_of_proxifiers
$ SOCKS_PROXY=localhost:1080 socksify curl http://www.example.com/curl: (7) Failed to connect to 0.0.0.1: Network is unreachable
15
( ꒪⌓꒪)
OpenSSH source code
• channels.c: channel_decode_socks5()
• https://github.com/openssh/openssh-portable/blob/master/channels.c
16
OpenSSH source code
• channels.c: channel_decode_socks5()
• https://github.com/openssh/openssh-portable/blob/master/channels.c
UDP非対応17
socksify + openssh = FAIL
• socksifyがDNS問い合わせをProxy経由で行おうとする
• DNS問い合わせはUDPなので、OpenSSHはエラーを返す
•即ち死
18
Force TCP DNS request
• tsocks
• http://sourceforge.net/projects/tsocks/
• res_init(3) をフックして、TCP問い合わせを有効にする
• redsocks
• http://darkk.net.ru/redsocks/
• DNS requestをキャッチしたら、truncatedフラグ付きの偽応答を返し、TCPで再度requestさせる
•どちらにしても、requestする側が外側のDNSサーバのアドレスを知っていなければならない
19
Force TCP DNS request
• tsocks
• http://sourceforge.net/projects/tsocks/
• res_init(3) をフックして、TCP問い合わせを有効にする
• redsocks
• http://darkk.net.ru/redsocks/
• DNS requestをキャッチしたら、truncatedフラグ付きの偽応答を返し、TCPで再度requestさせる
•どちらにしても、requestする側が外側のDNSサーバのアドレスを知っていなければならない
20
微妙…
SOCKS5 proxy-end DNS resolution
• SOCKS5ではDNS名前解決をProxy側で行うようにできる
• requestする側がDNSサーバのアドレスを知らなくても大丈夫
•とりあえずDNSはなんとかできる
• DNS以外のUDPは依然としてダメだが、問題になることは少ない
21
SOCKS5 proxy-end DNS resolution
• SOCKS5ではDNS名前解決をProxy側で行うようにできる
• requestする側がDNSサーバのアドレスを知らなくても大丈夫
•とりあえずDNSはなんとかできる
• DNS以外のUDPは依然としてダメだが、問題になることは少ない
22
いい感じ
proxychains-ng
• https://github.com/rofl0r/proxychains-ng
• proxy-end DNS resolution対応
•認証付きProxy対応
• HTTP、SOCKS4、SOCKS5混在の多段Proxy接続可能
23
proxychains-ng
• https://github.com/rofl0r/proxychains-ng
• proxy-end DNS resolution対応
•認証付きProxy対応
• HTTP、SOCKS4、SOCKS5混在の多段Proxy接続可能
$ proxychains4 curl http://www.example.com/[proxychains] config file found: /etc/proxychains.conf[proxychains] preloading /usr/lib/libproxychains4.so<!doctype html>...
24
proxychains-ng works, but …
•設定ファイルの書き換えが必須
•環境変数から設定できるようにしたい
•デバッグ出力を完全に消せない
•明示的に指定しない限り、入出力に触れないでほしい
•多機能すぎてオーバーヘッド大きそう
•せっかくならオーバーヘッドを最小化したい
•認証も多段接続もいらない
25
KNEESOCKS
kneesocks github
27
kneesocks github
28
SOCKS5 protocol in 1 minute
client proxy
1. support only NO-AUTH
2. ok, go with NO-AUTH
3. please connect to 203.0.113.1:80
4. succeeded
GET / HTTP/1.1
HTTP/1.1 200 OK
…
usual payload 203.0.113.1
29
Typical code for TCP connect
30
Typical code for TCP connect
31
Hooking libc functions
• libkneesocks.so
•改変したconnect, getaddrinfo (+ gethostbyname) を実装した共有ライブラリ
• kneesocks [command]
• LD_PRELOAD=libkneesocks.so [command] するだけのシェルスクリプト
• libkneesocks.soを優先的に読ませる
32
Outline of libkneesocks.so
• init()
• orig_connect = dlsym(RTLD_NEXT, “connect”)
• connect(s, {“203.0.113.1”, 80}, ...)
• connect_proxy(s, {“203.0.113.1”, 80}, ...)
• unset non-blocking flag
• orig_connect(s, {“127.0.0.1”, 1080}, ...)
• establish SOCKS connection for {“203.0.113.1”, 80}
• restore non-blocking flag
• return s
33
Hooking DNS lookup
•ドメイン名からIPアドレスへの変換はgetaddrinfo (or gethostbyname) で行われる
• getaddrinfoをフックして、常に0.0.0.1を返すようにする
• SOCKS4aの仕様にならう
•このとき、ドメイン名をThread Local Storageに記憶
• 0.0.0.1へのconnectが来たら、記憶したドメイン名をProxyに投げて解決させる
34
Request with domain name
• RFC 1928 - SOCKS Protocol Version 5
• http://tools.ietf.org/html/rfc1928
35
Request with domain name
• RFC 1928 - SOCKS Protocol Version 5
• http://tools.ietf.org/html/rfc1928
36
Request with domain name
• RFC 1928 - SOCKS Protocol Version 5
• http://tools.ietf.org/html/rfc1928
37
¥x0fwww.example.com
Typical code for TCP connectsaved_node = “www.example.com”return orig_getaddrinfo(“0.0.0.1”, ...)
orig_connect(s, {“127.0.0.1”, 1080}, ...)if dst addr is “0.0.0.1”:
establish SOCKS5 connection to saved_node (=“www.example.com”)
return s
38
Install, setup proxy and run
• sudo apt-get install build-essential
• git clone https://github.com/inaz2/kneesocks.git
• cd kneesocks
• make
• sudo make install
• ssh -D 1080 user@sv1 -f sleep 3600
• kneesocks curl http://www.example.com/
• sudo kneesocks apt-get update
• kneesocks git clone https://github.com/rapid7/metasploit-framework.git
• kneesocks bundle install
backgroundで1時間接続
39
Configuration via env variables
• socks_proxy=localhost:1080 kneesocks [command]
• localhost:1080 の部分を変える(上記はデフォルト値)
• DEBUG=1 kneesocks [command]
•標準エラー出力にデバッグログを吐かせる
$ DEBUG=1 kneesocks curl http://www.example.com/[kneesocks] getaddrinfo: node=www.example.com, service=80[kneesocks] connect: type=stream, family=2, address=0.0.0.1, port=80[kneesocks] connect_proxy: saved_node=www.example.com<!doctype html>...
40
WONTFIX
• gethostbyname2, gethostbyname_r, gethostbyname2_r
• GNU拡張(IPv6対応版とreentrant版)
• gethostbyname系関数はすでにobsoleteなので放置
• getaddrinfoを使わず、直接DNS requestを投げるプログラム
• dig, nslookup
• libcをstatic linkしているプログラム
• connectの前にgetaddrinfoを2連続で呼ぶプログラム
•よく使うものであったら教えてください
41
Pros and cons
• Pros
• SSHサーバさえ立っていれば、あとはローカルで完結
• DNSサーバのアドレスを知らなくてもよい
•任意のプログラムに統一的なインタフェースで使える
•オーバーヘッド最小
• Cons
• Linuxでしか使えない
•事前にコンパイルとインストールが必要
42
Recap
• Proxyプロトコルは楽しい
•標準Cライブラリ関数のフックは楽しい
• kneesocksお手軽便利
•「kneesocksを履かせる」という言い回し推奨
43
References
• ssh - Linux SOCKS5 tunneling not working with udp traffic - Super User
• http://superuser.com/questions/639425/linux-socks5-tunneling-not-working-with-udp-traffic
• How Socks 5 Works
• http://samsclass.info/122/proj/how-socks5-works.html
• malloc failure (その4) - Wataru's memo
• http://memo.wnishida.com/?date=20060730
• スレッドローカルストレージ(TLS) - Linuxの備忘録とか・・・
• http://wiki.bit-hive.com/north/pg/%A5%B9%A5%EC%A5%C3%A5%C9%A5%ED%A1%BC%A5%AB%A5%EB%A5%B9%A5%C8%A5%EC%A1%BC%A5%B8%28TLS%29
• opensshとproxychains-ngによるSOCKS Proxy経由のインターネット接続 -ももいろテクノロジー
• http://inaz2.hatenablog.com/entry/2014/08/20/004106
44
THANK YOU!@inaz2