CTF/포렌식

[SharkyCTF] Pain in the ass - 포렌식 / Wireshark / Blind SQL injection

SecurityMan 2022. 8. 10. 11:00

 

네트워크 패킷 포렌식 문제

 

문제 제목이 좀 당황스러운데

 

관용어로 아주 귀찮은 것을 뜻한다고 한다.

 

실제로 문제 풀이를 보면 그렇게 어렵진 않은데 아주 귀찮다..

 

반응형

 

문제 설명을 보면 어떤 사람이 데이터베이스를 덤프한것 같다고 한다.

 

그래서 어떤 자료들이 유출되었는지 알아봐달라고 요청한다.

 

 

주어지는 문제파일은 pain-in-the-ass.pcapng 파일이다.

 

pcapng 파일은 Wireshark 라는 도구를 이용해서 열어볼 수 있다.

 

 

와이어샤크로 패킷파일을 열어보면

 

여섯번째 패킷부터 바로 실마리가 보인다.

 

PostgreSQL 패킷 흔적이 보이는데

 

username이 d4rk2phi 인 계정의 비밀번호를 알아내기 위해

 

Blind SQL Injection 공격을 시도하고 있는 모습이 보인다.

 

Blind SQL Injection 은 SQL 인젝션 공격 기법 중 하나로

 

인젝션을 통해 데이터를 한번에 가져오기 제한되거나,

 

공격자 입장에서 쿼리의 참/거짓 여부만 알 수 있을 경우 사용되는 기법이다.

 

 

좀더 자세히 보기위해 pgsql 이라고 필터를 걸어주었다.

 

 

위 부분을 보면 확실히 Blind SQL Injection 공격을 하고있다는것을 알 수 있다.

 

SELECT * FROM users WHERE username = 'd4rk2phi' AND password ='' and 1=cast((SELECT table_name FROM information_schema.tables WHERE table_catalog=current_database() LIMIT 1 OFFSET 0) as int) and '1'='1';

 

SELECT * FROM users WHERE username = 'd4rk2phi' AND password ='' and 1=cast((SELECT table_name FROM information_schema.tables WHERE table_catalog=current_database() LIMIT 1 OFFSET 1) as int) and '1'='1';

 

이렇게 OFFSET 부분의 숫자가 하나씩 증가하는데

 

이건 information_schema.tables 에 저장된 table_name을 조금씩 쪼개서 가져오고 있는것이다.

 

 

실제 DB에서 해당 명령어를 입력해보면 직관적으로 알 수 있다.

 

 

이제 의미있는 쿼리를 찾아야 한다.

 

수많은 패킷들 중에서 맨 끝에 >Q 라고 표시되어있는 패킷이 실제 데이터베이스에

 

쿼리를 날리는 패킷이다.

 

Blind SQL Injection 공격 방식을 먼저 알아보자.

 

데이터베이스에 hello 라는 계정이 하나 저장되어있다고 가정한다.

 

공격자 입장에서는 데이터베이스에 대해 아무런 정보가 없기때문에 hello 라는 계정이 있는지 모르는 상태이다.

 

이때 공격자가 Blind SQL Injection 으로 계정명을 알아내는 방법은 아래와 같다.

 

계정명의 첫번째 글자가 a인가? -> False
계정명의 첫번째 글자가 b인가? -> False
계정명의 첫번째 글자가 c인가? -> False
계정명의 첫번째 글자가 d인가? -> False
계정명의 첫번째 글자가 e인가? -> False
계정명의 첫번째 글자가 f인가? -> False
계정명의 첫번째 글자가 g인가? -> False
계정명의 첫번째 글자가 h인가? -> True

계정명의 두번째 글자가 a인가? -> False
계정명의 두번째 글자가 b인가? -> False
계정명의 두번째 글자가 c인가? -> False
계정명의 두번째 글자가 d인가? -> False
계정명의 두번째 글자가 e인가? -> True

...

 

이런식으로 첫번째 글자부터 한글자씩 a부터 z까지 0에서 9까지 하나씩 대입해서 알아낸다.

 

True 가 나오면 다음글자로 넘어가는 방식이다.

 

주어진 패킷도 똑같다.

 

 

15751 패킷을 예를들어 본다.

 

이 패킷에서는 developers 테이블의 dev_username 컬럼어 저장된 첫번째 계정의 세번째 글자가 u 인지 물어보고 있다.

 

 

그다음에 있는 15752 패킷에서는 뭔지 알수 없지만 <T/C/Z 라는 문자열이 보이고,

 

 

바로다음있는 15776 패킷에서는 

 

developers 테이블의 dev_username 컬럼어 저장된 첫번째 계정의 세번째 글자가 v 인지 물어보고 있다.

 

u 인지 물어봤을때 False 가 나왔기때문에 다음 알파벳으로 넘어간 것이다.

 

 

15777 패킷에서는 아까 봤던 <T/C/Z 와 다르게

 

<T/D/D/D/D/C/Z 라는 문자열이 보이고,

 

 

다음 15801 패킷에서는

 

developers 테이블의 dev_username 컬럼어 저장된 첫번째 계정의 네번째 글자가 a 인지 물어보고 있다.

 

세번째 글자가 v에서 True가 나왔으니,

 

네번째 글자는 다시 a, b, c, d 순으로 True가 나올때까지 쿼리를 날리는 것이다.

 

그럼 이제 찾아야 할것은 명확해졌다.

 

<T<D<D<D<C<Z 라는 문자열이 보이면 직전에 보냈던 쿼리가 True가 나온것이므로

 

그 패킷들만 잘 모아주면 되는것이다.

 

 

쭉 내려가다보면 18348 패킷에서 부터 password 정보를 뽑아내기 시작한다.

 

여기부터 쭉 따라내려가면서 

 

<T<D<D<D<C<Z 가 보이면 그 바로 앞에있는 패킷 쿼리에 있는 비교문자열을 하나씩 이어붙여주면 된다.

 

 

첫번째 글자는 18798 패킷의 s

 

 

두번째 글자는 18998 패킷의 h

 

 

세번째 글자는 19273 패킷의 k

 

....

 

 

이런식으로 한글자씩 다 찾아주면 플래그를 얻을 수 있다.

 

진짜 아주 귀찮은 문제였다..

반응형