▶ SQLI(SQL Injection)

 

- 악의적인 사용자가 보안상의 취약점을 이용하여, 임의의 SQL 문을 주입하고 실행되게 하여

  데이터베이스가 비정상적인 동작을 하도록 조작하는 행위

 

▶ 코드 분석 

 

from core.libs import insert_to_params_urls // URL 입력 함수

 

from wordlists import sqli_payloads,sql_err // 페이로드 전달 함수

페이로드 전달해주고 오류 확인해주는 함수로 보임

 

from urllib.parse import urlparse // URL 구문 분석 함수

URL 6개의 구성 요소로 구문 분석하여 6개 항목 네임드 튜플 반환

 

from re import findall // 문자열 패턴 찾아주는 함수

 

from queue import Queue // queue 사용하기 위해 import

 

from threading import Thread // thread 다루기 위해 사용

 

 

 

def start(op,http):  op와 http 받아와서 시작

    for method in op['methods']:

        for payload in sqli_payloads: 전송된 데이터들 한 줄씩 받아오기

            n = insert_to_params_urls(op['url'],payload) 해당 url과 payload 함수로 전송

※ def insert_to_params_urls(url,text,single=True,debug=False):

        u = list()

        try:

            if len(url.split('?')) >= 1: url에서 '?'라는 문자로 나눈 개수가 1보다 크거나 같으면

                for param in url.split('?')[1].split('&'): 위에서 나눈 값에서 '&'라는 문자로 문자열 나누기

                     u.append(url.replace(param,param + text))

                      param 값을 param에 text를 더해준 값으로 바꿔준 후 list에 요소 추가

            return remove_dups(u) 리스트 반환

        except Exception as e: 예외처리 오류가 발생하면 해당 블록 수행

            if debug:

                print(f'[insert_to_params_urls] {e}')

            return list()

 

            for url in n:

                if method == 'GET': 만약 method가 GET 방식이라면 해당 method 값 반환

                                          send 함수로 연결되고 method방식과 url 전송

                    r = http.send(method,url)

                else: 아니면 url에서 '?' 문자로 나눠주고 url쿼리의 URL 항목을 튜플 형태로 분석하여 반환

                    r = http.send(method,op['url'].split('?')[0],body=urlparse(url).query)

                for s,v in sql_err.items(): item() 함수 이용하여 method, url, params, payload, match 한번에 반환

                    hmm = findall(v,r.content.decode('utf-8')) findall() 함수 이용(정규표현식에 해당)

                                                                          문자열 중 패턴과 일치되는 모든 부분을 찾아내는 함수

                    for i in hmm: 해당하는 값을 찾았다면 요소 반환

                        if i:

                           return {

                                    'method':method,

                                    'url':url.split('?')[0],

                                    'params':urlparse(url).query,

                                    'payload':payload,

                                    'match':v

                                    }

            return {}

 

 

 

def main(opts,r):

    c = start(opts,r) start 함수 호출

    if c:

        print(f'''[SQLI] {c["url"]} 반환값 있다면 url 출력

\tParams: {c["params"]}

\tMethod: {c["method"]}

\tPayload: {c["payload"]}

\tMatch: {c["match"]}

''')

 

'2021-1 STUDY > Web Programming Study' 카테고리의 다른 글

scant3r_SSTI  (0) 2021.05.05
Web Scanner  (0) 2021.04.11
Python  (0) 2021.03.27

▶ SSTI(Server-Side Template Injection)

 

- 공격자가 서버에서 임의의 코드를 실행할 수 있는 사용자 입력으로 템플릿 지시문을 주입할 때 발생하는 취약점

- 종류 : Ruby, Java, Twig, Smarty, Freemarker, Jade/Codepen, Velocity, Mako, Jinja2

 

- 정적 웹페이지 : 간단한 html을 사용해 페이지를 만들고 서버에 저장해 불러온 그대로의 모습을 보여주는 방식

- 동적 웹페이지 : 사용자가 작성하거나 선택한 이벤트에 따라 웹페이지의 구성과 내용이 달라지는 방식

- 템플릿 언어 : 언어의 변수 및 문법을 html 안에서 쓸 수 있도록 제공해주는 언어로 템플릿을 이용하면

                       구성하기 간단하면서 동적인 페이지를 만들 수 있음

 

- RCE(Remote Code Execution)가 템플릿에 들어가면 악의적인 행동 발생 가능

- RCE(원격 코드 실행) : 사용자와 동적으로 작동하는 템플릿의 방식에 나타나는 취약점으로 임의의 코드를 실행하도록

                                   하여 공격자가 프로세스를 제어할 수 있도록 만듦

 

→ 템플릿 주입은 웹 서버의 내부를 직접 공격하고 종종 RCE를 획득하여 취약점을 발생시킴

 

- Server-Side Template Injection 하는 방법

1. 구문을 입력하는 곳에 {{config}}나 주어진 단서를 활용하여 File.open('/etc/passwd')를 인젝션하여 디렉토리 확인

2. cat flag.txt 같은 코드를 rce하여 flag 값 뽑아오기

 

- SSTI 예제

?content={{7*7}}  → 49 출력

?content={{config.items()}}  → 딕셔너리 형태로 현재 설정되어 있는 config 출력

?content={{config.from_object('os')}}*  → os 라이브러리에 설정되어 있는 config 추가
?content={{''.__class__.__mro__}}  → root에 접근

슬라이싱 기법 이용하여 원하는 클래스 찾아보기

ex) {{''.__class__.__mro__[1]__subclasses__()[408]('ls',shell=True,stdout=-1).communicate()}} → 디렉토리 목록 출력

 

 

- SSTI 연습하기 좋은 ctf 문제

www.root-me.org/en/Challenges/Web-Server/ 

(Java - Server-side Template Injection)

 

 

 

 

▶ 코드 분석 

 

from urllib.parse import urlparse // URL 구문 분석 함수

URL6개의 구성 요소로 구문 분석하여 6개 항목 네임드 튜플 반환

 

from wordlists import ssti // ssti 취약점

 

from core.libs import alert_bug, insert_to_params_urls // ssti 경고창, url 주입

 

 

 

def __init__(self,opts,r):

     self.opts = opts

     self.http = r

     __init__함수로 opts와 r을 받아서 초기화 해줌

 

 

 

def scan(self,url,methods=['GET','POST']): 해당 url과 method 방식 불러옴

     for method in methods:

          for payload,match in ssti.items(): items() 함수 이용

          item() 함수 이용하여 payload와 match 쌍을 한꺼번에 출력

 

               nurl = insert_to_params_urls(url,payload) 해당 url과 payload 받아옴

            ※ def insert_to_params_urls(url,text,single=True,debug=False):

                    u = list()

                    try:

                         if len(url.split('?')) >= 1: url에서 '?'라는 문자로 나눈 개수가 1보다 크거나 같으면

                              for param in url.split('?')[1].split('&'): 위에서 나눈 값에서 '&'라는 문자로 문자열 나누기

                                   u.append(url.replace(param,param + text))

                                   param 값을 param에 text를 더해준 값으로 바꿔준 후 list에 요소 추가

                         return remove_dups(u) 리스트 반환

                     except Exception as e: 예외처리 오류가 발생하면 해당 블록 수행

                          if debug:

                               print(f'[insert_to_params_urls] {e}')

                          return list()

 

               for n in nurl:

                    if method == 'GET': 만약 method가 GET 방식이라면 해당 method 값 반환

                                               load() 함수로 이어지고 agent.txt 읽기 파일로 생성되는 듯(?)

                         r = self.http.send(method,n)

                        ※ send() 함수

                        def send(self,method='GET',url=None,body={},headers={},redirect=False,org=True):

                        try:

                             a = Agent()

                             if self.ragent:

                                  a.load()

                             if 'User-agent' not in headers.keys():

                                  headers['User-agent'] = a.random

                             if self.headers:

                                  for h,v in self.headers.items():

                                        headers[h] = v

                             if self.redirect:

                                  redirect = True

                             else:

                                  redirect = False

                             if self.timeout:

                                  timeout = self.timeout

                             else:

                                  timeout = 10

                             if type(self.proxy) == dict:

                                  proxy = self.proxy

                             else:

                                  proxy = {}

                             if org:

                                  if body:

                                       body = post_data(body)

                            else:

                                  body = {}

                            if method != 'GET':

                                  if body:

                                      pass

                                  else:

                                      body = post_data(urlparse(url).query)

                                      url = url.split('?')[0]

                            time.sleep(self.delay)

                            req = request(method, url, data=body, headers=headers, allow_redirects=redirect, verify=False,

                                                  timeout=timeout, proxies=proxy)

                            self.count += 1

                            if self.debug:

                                  print(f'--- [#{self.count}] Request ---')

                                  print(dump_request(req).decode())

                                  print('\n---- RESPONSE ----')

                                  print(dump_response(req).decode())

                                  print('--------------------\n\n')

                            return req

                      except Exception as e:

                            if self.debug:

                                  print(e)

                            return 0

 

                    else: 아니면 url에서 '?' 문자로 나눠주고 n쿼리의 URL 항목 튜플 형태로 분석하여 반환

                         r = self.http.send(method,url.split('?')[0],body=urlparse(n).query)

                    if r != 0: # 0 = Connection error: r이 0이면 connection error, 0이 아니면 각각 해당하는 값을 반환

                         if match in r.content.decode('utf-8'):

                              return {

                                           'http':r,

                                           'target':n,

                                           'match':match,

                                           'payload':payload,

                                        }

 

 

 

def main(opts,r):

s = Scan(opts,r)

v = s.scan(opts['url'],methods=opts['methods'])

if v:

alert_bug('SSTI',**v)

s라는 객체를 만들어 opts와 r을 전달해줌

v라는 객체에 해당 url과 methods(GET or POST)를 전달받고 만약 v가 존재한다면 SSTI 취약점 경고창 띄움

 

'2021-1 STUDY > Web Programming Study' 카테고리의 다른 글

scant3r_SQLI  (0) 2021.05.05
Web Scanner  (0) 2021.04.11
Python  (0) 2021.03.27

re 모듈의 주요 메소드

compile(pattern[,flags]) : pattern을 컴파일하여 정규식 객체를 반환

match(pattern,string[,flags]) : string의 시작부분부터 pattern이 존재하는지 검사하여 MatchObject 인스턴스를 반환

search(pattern,string[,flags]) : string의 전체에 대해서 pattern이 존재하는 지 검사하여 MatchObject 인스턴스를 반환

split(pattern, string[,maxplit=0]) : pattern을 구분자로 string을 분리하여 리스트로 반환

findall(pattern, string[,flags]) : string에서 pattern을 만족하는 문자열을 리스트로 반환

finditer(pattern, string[,flags]) : string에서 pattern을 만족하는 문자열을 반복자로 반환

sub(pattern, repl, string[,count=0]) : string에서 pattern과 일치하는 부분에 대하여 repl로 교체하여 결과 문자열을 반환

subn(patter, repl, string[,count=0] : sub과 동일하나 결과(결과문자열, 매칭횟수)를 튜플로 반환

escape(string) : 영문자 숫자가 아닌 문자들을 백슬래쉬 처리해서 리턴 (임의의 문자열을 정규식 패턴으로 사용할 경우 유용)

 

 

포트 스캐너

네트워크 소켓(socket)을 사용하여 특정 IP와 Port에 지속적으로 연결 요청을 보내는 작업을 수없이 반복하는 과정이 필요

socket 모듈을 import 한 후 connect() 함수를 호출하여 IP 주소와 포트 번호를 지정해주기

코드를 실행하면 TCP 연결을 수립하여 SYN/SYN-ACK/ACK하게 되고 send() 함수를 사용하여 데이터를 송신하거나 recv() 함수를 사용하여 데이터를 수신

개방되어 있지 않은 port에 대해서는 예외(exception)가 발생하는데, 소켓은 이것을 처리하기 위한 예외처리 루틴 수행(3-way handshake가 수립된 상태)

try~except 구문을 사용하여 닫혀 있는 포트를 무시하고 건너뛰는 형태로 작성할 수도 있음

이때 if문을 사용하여 open된 포트에 대해서만 결과물을 출력하도록 설정하고 조사하고자 하는 포트에 대해 리스트나 배열을 만들어둔 후 해당 값들에 대해서만 루프를 수행하여 조사하게 할 수도 있음

 

 

socket 모듈의 주요 메소드

socket() : 소켓 객체를 생성하는 함수

with as : 파일이나 소켓을 with as 구문으로 생성하면 후에 소멸할 때 close() 메소드를 호출하지 않아도 인터프리터가 자동으로 해줌

bind() : 서버를 만들 때 필요한 메소드로 튜플 형식을 받음

connect() : 클라이언트에서 서버에 접속하기 위해 AF가 인자로 들어가는데, (호스트 주소, 포트번호)로 구성된 튜플을 인자로 전달

listen() : 서버가 데이터 수신을 기다리는 상태로 인자 값으로 들어가는 숫자는 해당 소켓이 몇 개의 동시접속을 허용할 것인지의 의미

accept() : 소켓에 누군가가 접속하여 연결되었을 때 결과 값이 튜플로 return되는 함수로 return 값은 새로운 소켓과 상대방의 AF(Address Family)를 전달, 이 이후부터의 데이터 송수신은 새로운 소켓 이용

sendall()과 recv() : 데이터를 송수신하는 메소드, 클라이언트는 기존의 소켓으로 송수신을 하는 반면 서버는 accept()로 생성된 소켓으로 송수신을 함, 소켓은 턴 바이 턴 형식이기 때문에 데이터를 한 번 송신하면 다음은 수신해야 함

 

 

Nmap Port Scan

nmap을 사용하여 타겟 서버의 포트 개방 여부를 확인하고 어떤 프로세서가 러닝되고 있는지를 확인

 

 

1. os를 import 해줌

2. 첫번째 인자로 options, 두번째 인자로 ip address를 받는 함수 정의, 이때 –F 옵션을 사용하면 빠르고 개략적인 정보만을 보여줌

3. command에 nmap 명령어와 옵선, 스페이스와 IP 할당

4. command를 실행시키기 위해 popen() 메소드를 이용하여 지정

5. 위에서 지정된 process를 읽어들인 후 str() 메소드로 converting하여 results에 넣어주기

6. 저장된 results 반환

 

 

os 모듈의 주요 메소드

getcwd() : 현재 디렉토리 확인하기

chdir() : 디렉토리 변경

listdir() : 현재 디렉토리의 파일 목록 확인하기

read_csv() : csv 파일 호출

walk() : 파일이나 디렉토리의 목로을 얻기 위한 함수, 인수로 디렉토리명을 지저앟여 파일이나 특정 확장자의 목록, 파일 경로 취득 가능

path() : 파일이나 디렉토리의 존재를 확인하거나 지정한 경로의 파일명을 취득하거나 경로나 파일명의 결합 등의 용도로 사용

    exists() : 파일 및 디렉토리의 존재 확인. return값 Bool형

    isdir() : 디렉토리의 존재 여부 확인. return값은 Bool형

    isfile() 파일의 존재 여부를 확인. return값은 Bool형

    basename() : 지정된 경로의 파일명 리턴

    dirname() : 지정된 경로로부터 파일명을 제외한 것 리턴.

    split() : 지정된 경로의 파일명과 그 경로 리턴.

    splitext() : 지정된 파일의 확장자와 확장를 제외한 파일명까지의 경로를 리턴.

    join() : 경로와 파일명 등을 결합

environ() : 환경변수를 취득하거나 읽기 및 쓰기를 위해 사용, 환경변수란 시스템이 참고하고 있는 공통의 변수로 환경에 관련된 데이터나 공통으로 사용하는 파일의 경ㅇ로 등을 저장하기 위해 사용

 

 

robots.txt

웹을 만들 때 검색엔진에서 사이트를 프로그램으로 자동 저장하는 크롤링을 하는데 이때 민감한 페이지나 관리자 페이지 같은 것은 크롤링하지 못하게 텍스트 파일 형태로 작성해둔 것

 

 

1. urllib.request import

2. io import

3. url을 전달 받는 함수 정의

4. url이 ‘/’로 끝난다면 조건문 실행

5. 조건문이 참이면 path에 url 값 그대로 넣어주고 거짓이면 url 값에 ‘/’를 붙여 넣음

6. request 파일 만들기(어떤 사이트든 열어 그 값을 임의로 지정)

7. TextIOWrapper을 이용해서 data에 값 할당

8. return 값으로 위의 결과인 data 값 반환

 

 

sys 모듈 주요 메소드

파이썬 인터프리터를 제어할 수 있는 방법 제공

argv : 명령 행에서 인수 전달, 0번째는 스크립트 이름

exc_info() : 현재 발생한 예외 정보를 튜플로 반환 (예외가 없는 경우 None)

exit() : 강제로 스크립트 종료

path() : 자신이 만든 모듈 불러와서 사용하기

getrefcount(object) : 객체의 참조 카운트 값 반환

modules() : 현재 로딩되어 있는 모듈들을 사전 형태로 나타냄

 

 

파일 사용법

파일객체 = open(‘filename’,‘filemode’)

파일객체.write(‘string’)

파일객체.close()

with~as를 사용하면 자동으로 파일 객체를 닫을 수 있음

ex) with open(‘filename’,‘filemode) as 파일객체: 코드

파일객체.writelines(리스트) : 문자열로 된 리스트를 사용하여 파일에 한 번에 내용 작성

변수 = 파일객체.readline() or readlines() : 파일 내용 불러오기

pickle 모듈의 dump를 사용하여 객체들을 파일에 저장 가능

 

 

 

'2021-1 STUDY > Web Programming Study' 카테고리의 다른 글

scant3r_SQLI  (0) 2021.05.05
scant3r_SSTI  (0) 2021.05.05
Python  (0) 2021.03.27

1. 파이썬 개념 정리 & 예시

 

- github.com/jihyun28/Python/blob/main/practice.py

 

jihyun28/Python

Contribute to jihyun28/Python development by creating an account on GitHub.

github.com

(관련 강의 : www.inflearn.com/course/%EB%82%98%EB%8F%84%EC%BD%94%EB%94%A9-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B8%B0%EB%B3%B8/dashboard)

 

[무료] 파이썬 무료 강의 (기본편) - 6시간 뒤면 나도 개발자 - 인프런 | 강의

6시간. 여러분이 파이썬 개발자가 되는데 필요한 시간입니다. 핵심 내용만 선정 / 챕터마다 퀴즈 & 해설 / 실생활 기반 예제로 아주 쉽게 설명합니다. 그리고 완전 무료입니다., ★나도코딩님의

www.inflearn.com

 

 

 

2. 파이썬으로 웹 스크래핑하기

 

### 웹스크래핑과 웹크롤링

# 웹 크롤링 : 웹페이지 내에서 허용된 링크를 따라가면서 마구잡이로 데이터를 가져오는 것

ex) 서점이벤트

# 웹 스크래핑 : 웹페이지 내에서 필요한 부분만 가져오는 것

ex) 종이 한 장에 시험내용 정리

 

 

### HTML

※ html 공부 사이트 : w3school

 

 

### XPath

# 비슷한 태그나 요소가 있을 때 어떤 것을 지정한 것을 명확하게 하기 위해서 xpath를 사용
# xpath 구성
/학교/학년/반/학생[2]
//*[@학번="1-1-2] -> 밑의 그림과 같은 코드를 간소화 가능

/html/body/div/div/div/div/div/div/span/a...
//*[@id="login"] 

 

 

 

### 크롬

개발자도구 : [F12]

원하는부분 오른쪽 마우스 > Copy > Copy xpath

 

 

### Requests

#html 문서 정보를 가져오기 위해 사용하는 라이브러리

 

 

 

위와 같이 mynaver.html이라는 파일이 생성되고, 길이가 출력된 것으로 보아 웹 스크래핑이 잘 진행된 것을 확인할 수 있다.

 

 

### 정규식

※ 정규식 공부 사이트 : w3school, python re

# . : 하나의 문자를 의미 ex) ca.e -> care, cafe (O) | caffe (X)

# ^ : 문자열의 시작 ex) ^de -> desk, destination (O) | fade (X)

# $ : 문자열의 끝 ex) se$ -> case, base (O) | face (X)

 

print(m.group()) # 일치하는 문자열 반환

print(m.string()) # 입력받은 문자열

print(m.start()) # 일치하는 문자열의 시작 index

print(m.end()) # 일치하는 문자열의 끝 index

print(m.span()) # 일치하는 문자열의 시작과 끝 index

 

# 1. p = re.compile("원하는 형태")

# 2. m = p.match("비교할 문자열") : 주어진 문자열의 처음부터 일치하는지 확인

# 3. m = p.search("비교할 문자열") : 주어진 문자열 중에 일치하는 것이 있는지 확인

# 4. lst = p.findall("비교할 문자열") : 일치하는 모든 것을 "리스트" 형태로 반환

 

 

### User Agent

#user agent 확인

https://www.whatismybrowser.com/detect/what-is-my-user-agent

 

 

### 네이버 웹툰 스크래핑

 

인기급상승 만화 - 인기순

 

 

인기 급상승 부분에 해당하는 코드

 

 

 

 

위의 코드를 실행한 결과는 다음과 같다.

 

 

 

위의 코드를 실행한 결과는 다음과 같다.

 

 

 

위의 코드를 실행한 결과는 다음과 같다. 

 

 

 

위의 코드를 실행한 결과는 다음과 같다.

 

 

 

 

 

(관련강의 : www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9B%B9-%EC%8A%A4%ED%81%AC%EB%9E%98%ED%95%91/dashboard)

 

[무료] 파이썬 무료 강의 (활용편3) - 웹 스크래핑 (5시간) - 인프런 | 강의

HTML 기초부터 고수들의 스크래핑 비법까지, 모두 알려드리겠습니다. 이 영상 하나면 충분합니다., 재미있고 유용한 웹 스크래핑, 각종 데이터를 내 손으로 다루고 얻어보세요! 혹시 늑대와 일곱

www.inflearn.com

 

'2021-1 STUDY > Web Programming Study' 카테고리의 다른 글

scant3r_SQLI  (0) 2021.05.05
scant3r_SSTI  (0) 2021.05.05
Web Scanner  (0) 2021.04.11

+ Recent posts