출처: http://noplanlife.com/?p=1339

 

웹 취약점 점검에 Burp-Suite와 같은 상용(혹은 free) Proxy 도구를 많이 사용하긴 하지만
특정 영역에서 취약점을 발견했을 경우 상용 도구에서 제공되는 부가기능(Intruder 등)을 쓰기 보다는
Python을 통해 직접 도구를 제작하는 것이 효율적일 때가 있다.

파이썬에서 http 통신을 위해 가장 기본적으로 사용되는 라이브러리에는 socket, urllib(2) 등이 있지만
아래 소개할 requests 를 사용하면 아주 간편하고 빠르게 공격 도구를 제작할 수 있다.

본 포스팅 내용은 아래 공식 페이지 내용을 참고하여 작성하였음을 미리 밝힌다.
http://docs.python-requests.org/en/latest/

 

설치 방법

pip 혹은 easy_install 도구를 통해 간편하게 설치가 가능하며, git 을 통한 수동 설치도 지원한다.

설치가 끝나면 정상적으로 라이브러리가 import 가 되는지 파이썬을 열어 확인해보자

오류 없이 정상적으로 설치 된 것을 확인할 수 있다.
이제 본격적으로 requests 라이브러리를 활용해보도록 하자.

 

GET / POST 요청(request)과 응답(response) 받기

라이브러리를 불러오는(Importing) 것은 다음 한 줄이면 충분하다.

공격 대상 웹 서비스가 GET 메서드를 지원하는 경우 다음과 같이 Request를 생성한다.

url을 별도로 분리해 놓은 것은 추후에 코딩시에 유연성을 높이기 위해서이며,
직접 get(‘대상주소’) 형식으로 입력해도 무방하다.

위와 같이 get 메서드를 호출하게 되면 응답 값에 대한 객체가 “r” 에 부여되며,
앞으로도 이 객체를 사용하여 url 에 관련된 정보를 수집할 수 있다.

GET 이 아닌 POST 방식의 경우 다음과 같이 파라미터를 딕셔너리 형태로 정의한 후
post 메서드 호출 시 인자값으로 전달하면 된다.

Response(응답) 값은 아래와 같이 r.text를 통해 가져올 수 있다.

json 타입의 Response의 경우도 r.json()을 통해 가져올 수 있으며, 응답값 내용을 분석 후
원하는 값을 Parsing 하는 작업도 간편하게 할 수 있다.

 

Custom Header 설정

requests 라이브러리는 사용자가 직접 Header 값을 작성하여 Request 전송이 가능하다.
Post 요청시 파라미터 값을 넣었던 방식과 동일하게 딕셔너리 형태로 header 를 작성한 후
GET / POST 호출 인자값에 추가시켜준다.

 

Bruteforce 공격도구 제작하기

파이썬 라이브러리는 사용하기 매우 직관적이기 때문에 위에서 다룬 내용만으로도
충분히 공격 도구를 제작할 수 있다.

실제 케이스를 바탕으로 좀 더 자세히 샆펴보도록 하자.


“특정 웹사이트를 대상으로 모의해킹을 하던 도중, [회원 정보 조회] 페이지에 대한
세션 처리가 미흡하여 타 회원의 정보를 조회할 수 있는 취약점을 발견하였다.
단, 타 회원의 정보는 8자리 랜덤 영문자+숫자 포맷으로 구성되어 있었다”


 

실제 웹사이트 모의해킹을 하다보면 위와 같은 케이스를 매우 빈번하게 접할 수 있다.
특히, 회원 정보 / 상품구매 이력 등 개인의 민감한 정보와 관련된 페이지에서
인증 처리가 미흡하거나, 회원 구분을 단순 숫자값으로 구성하고 있을 경우는 문제가 될 수 있다.

취약한 웹 서비스의 주소를 “www.example.com/info/profile/{profile-id}” 라고 가정한 후,
공격 코드를 한단계씩 만들어 보자.

먼저 회원 profile-id 를 구성하는 랜덤 8자리 영문자+숫자 조합을 만들기 위해
파이썬의 itertools 라이브러리를 사용해보도록 하자.

8자리 id가 생성되긴 하나 itertools 라이브러리 특성상 알파벳 순차적으로 생성되기 때문에
공격용으로 쓰기에는 적절해보이지 않는다 (물론 상황에 따라 이것이 더 효율적인 경우도 있다)

random 라이브러리를 사용하여 다른 방법으로 id를 생성해보았다.

확률적으로 어떤 것이 profile-id를 찾는데 더 효율적인지는 확인할 수 없으나,
itertools의 순차적으로 생성된 id가 아닌 랜덤하게 생성된 id를 사용하여 도구를 만들 예

이제 남은 것은 앞서 다룬 Requests 라이브러리를 통해, 임의로 생성한 profile-id를 요청한 후,
Response Code를 통해 의미있는 페이지와 아닌 것을 구분하기만 하면 된다.

남은 코드를 완성해보도록 하자.
Custom Header의 경우 Burp Suite를 통해 Request 부분을 그대로 복사한 후,
그대로 Dictionary 타입으로 변환하여 넣어주면 된다. (아래 코드 헤더 영역 참조)

 

공격 환경이 Proxy Server를 사용하고 있을 경우에는 request 옵션에 “proxies” 를 넣어주면
정상적으로 커넥션을 맺을 수 있다.

이상으로 파이썬의 requests 라이브러리에 대해 간단하게 알아보았다.
사실 urllib(또는 urllib2) 가 사용하기 더 편하다면 그것을 사용해도 무방하다.

위 예제는 PoC 목적으로 짜여진 코드이므로, 직접 사용하기 보다는
해킹 대상 서버와 주고 받는 값들을 우선적으로 면밀히 분석한 후, 최종 자동화툴을 만들 때
참고해서 사용하는 것이 좋겠다.

출처: http://creativeworks.tistory.com/entry/PYTHON-3-Tutorials-24-%EC%9B%B9-%ED%81%AC%EB%A1%A4%EB%9F%AClike-Google-%EB%A7%8C%EB%93%A4%EA%B8%B0-1-How-to-build-a-web-crawler




뉴스 크롤링 관련


//구글 뉴스 크롤러

https://pypi.python.org/pypi/google_news_crawler


// 뉴스 크롤러

https://github.com/codelucas/newspaper



 

안녕하세요. 몇일동안 본업(?)에 매진하느라 소홀했던 튜토리얼을 다시 작성하려 합니다. 간혹 메일로 문의를 주시는 분이 계신데, (메일은 어떻게 아셨지 -_-a) 그냥 여기에 댓글을 다셔도 가능하면 답을 달아 드립니다. 긴급한(!) 일이 아니라면 메일은 삼가해 주셨으면 합니다^^;. 서두가 길었네요. 시작해 보겠습니다.

이번 시간에는 인터넷 상에 있는 자료(데이터: 글 + 이미지 + 파일 등등) 들을 파이썬을 이용해서 긁어오는 것을 하겠습니다. 우리가 잘 알고 있는 구글의 검색 시스템도 시시각각 인터넷상에 올라오는 글들을 크롤러(로봇)가 링크를 타고 타고해서 DB(데이터 베이스)에 잘 저장을 해 둔것을 사용자들이 찾는 시스템입니다. 여타 검색엔진과 다르게 구글이 크게 성장할 수 있었던 요인 중 하나는 사람의 손을 별로 타지 않은, 양질의 검색 결과를 보여주었기 때문입니다. (한국의 몇몇 검색 포털과는 다르게....). 이번에는 이렇게 크롤러(로봇)들이 웹을 돌아 스크랩(긁어오기)을 하는 것을 특정 사이트만을 크롤링 해 보도록 하겠습니다. 

엉뚱한 사이트를 크롤링하는 것 보다  본 사이트의 글 제목과, 본문을 파이썬으로 가져오는 것을 구현해 보겠습니다. 이를 각 개개인이 원하는 형태로 응용을 하면 꽤(?) 유용한 자신만의 AP(Applications)을 만들어 사용하실 수 있을 겁니다.

1. Coding


파이썬에서 웹상의 데이터를 처리할 때 필요한 모듈인 requests 를 import 해줍니다.

웹의 언어는 HTML, CSS, JavaScript 등 웹언어를 기반으로 하고 있는데, 이를 사람이 보기 좋게 가독성을 높여줄 수 있는 모듈인 BeautifulSoup 를 불러오도록 합니다. 

어떤 특정 웹 페이지를 크롤할 수 있게 하는 함수를 정의 합니다. parameter는 최대 크롤할 페이지 수를 받습니다.

크롤링 할 첫 페이지를 1부터 하게 변수 page에 1을 저장합니다. 그리고 초기 입력해 줄 페이지가 최대 크롤할 페이지 보다 작을 동안 계속 크롤할 수 있게 while 반복문을 사용하였습니다.

그리고, 크롤할 사이트를 본 블로그로 하고 그 뒤에 페이지 번호를 합쳐 저장한 값을 변수 url 에 저장하도록 하였습니다.

타겟 url의 데이터를 파이썬으로 처리하기 위해 데이터를 불러오려고 하는데, 이 때 아래와 같이 requests.get(url)으로 데이터를 가져옵니다. 이렇게 받은 데이터를 source_code 라고 하는 임의의 변수에 저장하도록 하였습니다.

이렇게 저장된 source_code의 텍스트 부분만을 처리하여 plain_text에 저장을 하겠습니다.

그런데 이렇게 저장된 plain_text 는 아래 그림처럼 가독성이 엉망인 상태입니다.

위 그림처럼 무슨 내용이 있는지 잘 알수가 없는 데이터를 사람이 읽기 쉽게 해주는 파이썬 모듈이 초기에 불러온 BeautifulSoup 이라는 모듈입니다. 

아래와 같이 가독성을 높여주기 위해 BeautifulSoup(  타겟, parser ) 를 처리하여 임의의 변수인 soup에 저장을 하도록 하였습니다.

그런데 위 그림에서  'lxml'이라고 하는 parser를 사용하였는데, 이는 파이썬 기본 내장 파서인 html.parser보다 처리속도가 월등히 빠르기 때문이다. 추후에 여러 parser의 장단점을 비교하는 글을 따로 올리도록 하겠습니다.


여기까지 결과를 터미널을 띄워서 따로 결과 확인을 해보도록 하겠습니다.

첫 번째 터미널 결과보다 훨씬 가독성이 좋은 html 코드가 되었네요.



위 그림에서 각 페이지에서 타이틀(제목)에 해당하는 HTML 태그가 h2 아래에 있는 a 태그안의 값이므로 아래와 같이 soup.select('h2  > a') 값으로 찾을 수 있습니다. 

보다 자세한 BeautifulSoup 사용법을 확인하시면 다양한 방법으로 데이터를 가져올 수 있습니다. 

이렇게 찾은 타이틀의 HTML 값에서 href 값을 추출하여 기본 URL 과 합쳐줍니다. 그런 후에 href 변수로 저장을 하였습니다.

그리고 타이틀(제목)을 변수 title 에 저장을 하게 아래 코드처럼 만들었습니다.

이제 확인을 위해 프린트 함수를 사용하여 여기까지 잘 진행이 되었는지 출력해봅니다.

위와 마찬가지로 터미널로 여기까지의 진행상황을 확인해 보았습니다. 결과값이 잘 나오고 있군요. 첫번째 페이지의 URL 값과 타이틀이 출력이 되었습니다.

이제 이렇게 처리된 사항에서 while 반복문이 무한반복이 되지 않게 하기 위해 page += 1 을 주었습니다. 이렇게 함으로 인해, 초기 페이지부터 지정한 특정 페이지 범위의 모든 타이틀과 URL 값을 출력하게 하였습니다.

함수를 만들었으니 이제 함수 호출 및 실행을 해봐야겠죠? 아래와 같이 함수를 호출하였습니다. 이렇게 하면 1페이지만 실행이 될 것입니다.

위 코드의 결과값입니다. 첫 페이지의 URL , 타이틀(제목)이 잘 출력이 되었습니다. 

초기 스크롤 할 페이지는 1로 그대로 두고, 9 페이지 까지 스크롤하게 max_pages 값을 변경하였습니다.

그 결과 아래 그림처럼 1~9페이지까지 URL, Title 이 잘 출력이 되었습니다.

2. Comments


위의 결과를 보다 효율적으로 사용하기 위해서는 다음시간에 다룰 본문 내용을 크롤링하게 하여 URL, TITLE, 본문내용, etc. 를 파일의 형태롤 저장을 해두면 보다 효율적이고 효과적인 데이터 활용이 될 것입니다. 

이제는 2번째로 본문을 크롤링하러 가 보겠습니다. 아래 링크를 누르시면 됩니다.

[PYTHON 3] Tutorials 25. 웹 크롤러(like Google) 만들기 2 - How to build a web crawler 

  1. 2019.03.15 15:56

    비밀댓글입니다

출처:http://stackoverflow.com/questions/14681096/typeerror-isinstance-arg-2-must-be-a-type-or-tuple-of-types


typeError: isinstance() arg 2 must be a type or tuple of types




>>> names=['jhon','jack']
>>> isinstance(names,list)
Traceback (most recent call last):
  File "<pyshell#291>", line 1, in <module>
    isinstance(names,list)
TypeError: isinstance() arg 2 must be a type or tuple of types
>>> 

에러 해결 방법
isinstance(names, __builtins__.list)
list이름을 __builtins__.list로 바꿔준다


__author__ = 'Administrator'
import xlrd
from paramiko import SSHClient
from scp import SCPClient
import paramiko

def scp_go(ipaddr,usename,pww,spath,opath):
ssh = SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ipaddr,username=usename,password=pww)

ssh.exec_command('mkdir sg_test')
# SCPCLient takes a paramiko transport as its only argument
scp = SCPClient(ssh.get_transport())

scp.put(spath,'sg_test')
ssh.exec_command('chmod 755 sg_test/linux.sh')
stdin,stdout,stderr = ssh.exec_command('cd ./sg_test; ./linux.sh')
print stdout.readlines()
ssh.exec_command('cd ./sg_test; mv *.txt '+ipaddress+'.txt')

scp.get('sg_test/'+ipaddress+'.txt',opath)

ssh.exec_command('rm -rf ./sg_test')

scp.close()

print 'input excel file path'
print 'ex) d:\\000\id_info.xlsx'
xlpath = raw_input("input excel file path: ")

print 'input .sh file path'
print 'ex) d:\\000\linux.sh'
shpath = raw_input("input .sh file path: ")

print 'input output file path'
print 'ex) d:\\000'
outpath = raw_input("input output path: ")


wb = xlrd.open_workbook(xlpath)
ws = wb.sheet_by_index(0)
ncol = ws.ncols # number of col
nlow = ws.nrows # number of low



print "-------- Starting engine.. --------"

i = 0
j = 0
low = []
list = []
while i < nlow :
while j < ncol :
if j == 0 :
ipaddress = str(ws.row_values(i)[j])
elif j == 1 :
name = str(ws.row_values(i)[j])
elif j == 2 :
pw = str(ws.row_values(i)[j])
j += 1
scp_go(ipaddress,name,pw,shpath,outpath)
i += 1
j = 0

print "-------- Finished !! --------"


from paramiko import SSHClient
from scp import SCPClient
import paramiko

# id info
ipaddress ='192.168.17.131'
name = 'root'
pw = 'horae'

ssh = SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ipaddress,username=name,password=pw)

ssh.exec_command('mkdir sg_test')
# SCPCLient takes a paramiko transport as its only argument
scp = SCPClient(ssh.get_transport())

scp.put('d:\\000\linux.sh','sg_test')
ssh.exec_command('chmod 755 sg_test/linux.sh')
stdin,stdout,stderr = ssh.exec_command('cd ./sg_test; ./linux.sh')
print stdout.readlines()
ssh.exec_command('cd ./sg_test; mv *.txt '+ipaddress+'.txt')

scp.get('sg_test/'+ipaddress+'.txt','d:\\000')

ssh.exec_command('rm -rf ./sg_test')


scp.close()


https://github.com/jbardin/scp.py

출처: https://gist.github.com/mlafeldt/841944


scp_demo.py


#!/usr/bin/env python

import sys, paramiko

if len(sys.argv) < 5:
    print "args missing"
    sys.exit(1)

hostname = sys.argv[1]
password = sys.argv[2]
source = sys.argv[3]
dest = sys.argv[4]

username = "root"
port = 22

try:
    t = paramiko.Transport((hostname, port))
    t.connect(username=username, password=password)
    sftp = paramiko.SFTPClient.from_transport(t)
    sftp.get(source, dest)

finally:
    t.close()



ssh_demo.py


#!/usr/bin/env python

import sys, paramiko

if len(sys.argv) < 4:
    print "args missing"
    sys.exit(1)

hostname = sys.argv[1]
password = sys.argv[2]
command = sys.argv[3]

username = "admin"
port = 22

try:
    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.set_missing_host_key_policy(paramiko.WarningPolicy)
    
    client.connect(hostname, port=port, username=username, password=password)

    stdin, stdout, stderr = client.exec_command(command)
    print stdout.read(),

finally:
    client.close()


출처:http://lifepolio.tistory.com/12



먼저 비쥬얼 2010 파일을 다운로드 후 진행을 하자.




C:\python\scripts 위치에서 pip instal paramiko 실행







모든 진행이 완료되면 파이썬 소스에 import paramiko 를 해서 잘 적용 되었는지 확인한다.  

+ Recent posts