constWORLDant

prob2 하기 전 공부한 것 본문

0x09 WEB Hacking 기초공부

prob2 하기 전 공부한 것

data type ConS_tanT 2018.07.26 10:44

상황 부여 : 일반 웹페이지로 보인다.


소스코드를 보니 index, about, member, research , fun, contact 이런게 있고

가장 중요해보이는 admin이 있다. 


1. admin 접근 -> admin부분은 php가 붙어있지 않다.

php는 단지 확장자 일뿐이라는건가? 

어떤부분인지 감은 안오지만, tomcat이런데 연결되어있으면 php가 붙어있지 않아도 php로 

받아들이는건가? 아직은 웹 공부를 안해본 상태라 잘 모르겠다 그냥 상상만 하고 넘어가는걸로 


admin에 접근을 하니 계정을 입력하는 부분이 있다.


2. board 부분 

board에 단 하나의 글만 올라가 있다.

url을 보니 예는 파라미터가 보이는것으로 보아 get 방식을 택하고 있나보다


그럼 각 각의 웹페이지마다 post와 get를 동시에 사용할 수 있다는 생각을 하였다.


흠... 글을 하나 올려서 접근 우회를 해보려 했는데 글을 올릴 수가 없다!!!!


다시 admin 부분을 유심히 보면서 생각을 해봤다.


우선 피들러를 통해 보니까 password만 보이고, 계정은 admin으로 고정으로 보여졌다.


웹은 우선 내가 아는 지식에 의하면 tomcat같은 것을 구동시키고 SQL Service (오라클이든 MYSQL이든 MSSQL이든) 하나를 연결시켜 데이터베이스를 생성한다.


데이터베이스에는 계정의 정보가 담겨있을 것이다. 



시행 착오를 통해 배운 SQL Injection.

admin 이 부분이 벡터가 아니라고 생각한 것은 착각이었다.

<form method=post action=index.php name=admin>

<input type=password name=password size=10><input type=submit 

type이 password인것은 프로그래밍에서 *표시를 나게 하는 것이다. 


만약, c언어에서 입력 시 *표시 나게 구현하려면 getch함수와 출력함수를 적절히 사용하면 된다. php는 자동으로 타입을 정해주니 편리하다고 생각된다. 


name은 말그대로 변수 명 웹은 이런식으로 변수와 타입을 만드는 것을 파악 


그리고 submit은 이벤트핸들러로 판단된다. 

즉, 특정 조건이 참이 될 때 submit 이벤트로 인해 정답을 도출할 것이다.


post라는 포맷은 get과 다르게 url에 파라미터가 보이지 않았다.


리버싱과 다르게 비밀번호 관련 키젠 루틴이 보이지가 않는다. DB에 촥촥 저장 되어 있기

때문이라고 보여진다. 흐름만 잘 파악하면 리버싱보다 쉬울것같다 ㅋㅋㅋㅋ (허언)


그럼 이 벡터는 아닌것으로 간주하고 다른 부분을 보기로 하였다.


/bbs/index.php (board) 이 부분에서 데이터베이스(DB)를 사용하는 것으로 추정되어 sql injection을 공부해보았다.


sql injection ? 

웹 어플리케이션에 대해서 가해지는 흔한 공격 기법이라고 한다.

시스템해킹에서 BOF가 가장 흔한 공격 기법이든 이 친구도 그런 류에 속하나 보다.


네임에 특정 아이디를 기입하고 패스워드에 ' or 1=1-- 이런것을 입력

하는 기본 예제를 보았다. 

이 블로그는 무슨 원리 설명도 없고 그냥 입력하면 뚫려염~ 이렇게 되어있었는데 

다른 블로그를 참조하기 전에 잠시 생각을 해보는 시간을 가져보았다.

게싱을 때려보면, or연산이 있으니 둘 중 하나만 참이면 특정 기능을 수행할 것이라고 

판단 하였다.


또 다른 블로그도 참조해 보았는데 여기서는 secure coding을 알려주었다.

prepared statement (준비 된 선언)

POD나 MySQLi 이라는 2가지 방법이 존재하였다.


1. POD

// PDO 방법


$username = $_POST["username"];

$password = $_POST["password"];


$pdo = new PDO('mysql:dbname=testdb;host=127.0.0.1', 'user', 'password');


// PDO의 객체 pdo를 생성하고 pdo가 참조하고 있는 setAttribute 메서드에서

false라는 인자값을 발견하였다.

// 메서드를 검색해보니 데이터베이스 핸들 속성을 설정하는 것이었다.

// 프로그램에서 핸들은 중요한 역할을 부여한다.

// 가령, 메모리 후킹 시 핸들 값을 이용하는 것 처럼 

// value값이 FALSE인 것으로 보아 핸들을 사용하지 못하게 하는 것으로 보여진다.

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);


// sqli가 일어나는 원인인 or를 패치하였다. 

$st = $pdo->prepare('SELECT * FROM users WHERE username=:username AND password=:password');


// 파라미터를 bind 한 다음 실행시킨다.

$st->bindParam(':username', $username);

$st->bindParam(':password', $password);

$st->execute();


var_dump($st->fetchObject());


2. MySQLi 

$username = $_POST["username"];

$password = $_POST["password"];


$mysqli = new mysqli('localhost', 'username', 'password', 'testdb');


// sqli가 일어나는 원인인 or를 패치하였다. 

// 위의 pdo와의 차이점은 mysqli는 prepare라는 메서드를 참조하는 것은 같지만

// mysqli는 특별히 setAttribute는 하지 않는 것으로 보인다.

$st = $mysqli->prepare('SELECT * FROM users WHERE username=? AND password=?');

$st->bind_param('s', $username);

$st->bind_param('s', $password);

$st->execute();


$result = $st->get_result();

var_dump($result->fetch_object());


무엇이 더 좋은지 적혀있는 부분이 있었는데 여기서 mysql 함수라는 것은 

더이상 사용하지 않는 절차지향 인터페이스임을 알게 되었다. 

mysql함수에서 SQL 인젝션을 막기위해서는 변수를 "수동"으로 escape해야한다.


MySQLi는 mysql을 대체하기 위한 "객체지향" 인터페이스였다.

위에서 공부한대로 Prepared Statement를 지원한다.


PDO는 PHP Data Objects라고하는데 일반적인 데이터베이스 인터페이스이다.

이 역시 객체지향이다. Prepared Statement도 지원한다.


pdo를 더 추천한다고한다. 

그 이유는 더 많은 것을 지원한다라고 되어있는데 꼭 많은 것을 지원해야 좋은 걸까라는

의구심이 조금은 들기는 한다.


이번엔 공격 방법을 알고 싶어 공격방법도 공부하였다.


1. 테이블 명을 알아내기

데이터베이스를 생성할 때 테이블을 꼭 만들어둔다. 이건 마치 구조체와 같다고 보여진다.

하나의 테이블에 여러가지의 정보를 넣어두기도 함과 동시에 그 정보들의 데이터형이 다 

다르기 때문이다.

우리가 실제로 계정을 생성할 때 id,password,나이 뭐 이런것들이 데이터형이 조금 씩 다르다고 생각된다. id,password는 우선 문자열일테고, 나이는 integer일 것이다.


having이라는 명령어를 사용한다고 한다.

이런 방식은 Error based방식에 속한다. 

에러 유발 -> 정보 추출 -> DB명, Table, Column, Data 탈취 가능성 


having의 뜻을 풀어보면 가지고 있다라고 표현할 수 있다.

즉 해당 웹 페이지의 데이터베이스에 가지고 있는 것을 보겠습니다. 라고 보여진다.


추가적으로 공부를 더 해보니 "having은 group by가 사용된 SQL문에서 필터링이나

어떤 조건을 줄 때 사용하는 구문이다" -> 반드시 "GROUP BY"와 함께 사용해야 한다.


해커는 반드시 사용해야 하는 규칙을 가지고 놀 수 있어야 한다.

즉, HAVING구문을 기입할 때 GROUP BY를 제외하고 실행하게 되면 에러를 유발 시킬 수 있고 그 에러를 통해 필요한 정보를 수집할 수 있다.


블로그에서 보여지는 예시는 username : ' having 1=1-- 

음 여기서도 ' 와 1=1--이 쓰임을 보았다. 

우선, 직관적으로 해석해보면 이 데이터베이스에 있는 username 섹션들을 모조리 읽어

와라로 보여진다. 


정확한 뜻은 having은 group by에 의한 결과를 제한할 때 사용한다고 한다.

group by는 데이터를 원하는 그룹으로 "나눌 수 있다"

그 나눈 그룹에서 having 절에 적어둔 조건과 맞지 않은 것은 다 버릴 수 있다.


만약 해당 웹 사이트의 DB에 name, password, age가 있을 때 

password와 age를 굳이 보고 싶지 않을 때 사용할 수 있을 것 같다.




공부 한 것을 토대로 시나리오를 작성해보았다.


첫 번째 상황 : 해커는 이 db에 users라는 테이블이 있음을 알고 있다.

★해당 사이트의 테이블 명을 알고 싶을 때는 union이라는 명령문을 기입해도 된다.


example)


select * from users where username = ' +username+ ' and password = ' +password+' + and age = ' +age' 


user라는 테이블에 username, password, age라는 필드가 들어있는데 

이 중에서 username만 보고 싶다면 다음과 같이 세팅할 수 있다.


select * from users where username = '' having 1=1 -- 

여기서 --의 뜻을 알 수 있었다 

sql에서의 --는 주석이다.

sql에서의 '는 문자 데이터 구분 기호이다.


즉 users 테이블에 여러개의 필드가 존재하는데 그 필드 중에 username을 제외한 

필드는 보여주지 않아도 된다. (select문은 출력해주는 아이) 


result)

만약 저렇게 코딩을 하였을 때(혹은 sql 명령문을 기입하였을 때)

'users.id' 열이 집계 함수에 없고 GROUP BY 절이 없으므로 SELECT 목록에서 사용할 수 없다. 이런 에러가 출력 될 수 있다고 한다.


프로그래밍을 할 때는 이러한 에러를 잘 파악할 줄 알아야 한다고 생각한다.

이 에러를 분석해보면 이러한 결과를 도출 할 수 있다.


<도출 결과>


1. 현재 DB에는 users라는 table이 있다.

2. users Table에는 id이라는 필드가 있다. 


<의문>

만약, select * from users라고 명령문을 기입하지 않고

select * from user라고 했을 때 에러가 출력된다고 가정하면 

'users.id'열이 집계 함수에 없고라는 말이 나올 것인가?

그렇게 되면 union을 굳이 쓸 필요가 없어지지 않는가?


두 번째 상황

지금 해커는 users라는 table에 id라는 필드가 있음을 알아내었다. 


해커가 과연 그 필드만 알고 넘어갈까? 그렇지 않다. 사람의 욕심은 끝이 없기 때문에 

필드를 알았으면 다른 필드까지 알고 싶어할 것이다.


필드 명을 알아낼 때는 group by절을 사용한다. 

위에 공부한 내용으로는 having을 통해 group by절의 결과를 제한한다. 

만약 users.id 이후 만족해야 하는 사항을 sql select문이 만족하지 못한다면 

이전 예시 처럼 에러를 출력할 것이다.


example)

select * from users where username = ''group by users.id having 1=1-- 


SQL 구문해석)

users 테이블에서 username이라는 필드를 검색하여 모두 출력하라.

단, users.id 이외의 사항은 필터를 걸자. 


의문 1)

필터를 걸었는데 앞의 명령을 보면 select *로 되어있다.


의문 1-1) 

select * 과 having 1=1--  둘 중 우선순위는 누구인가?


result)

'users.username'열이 집계 함수나 group by 절에 없으므로 select 목록에서 

사용할 수 없습니다.


도출 된 result를 통해 다시 바라본 기존에 제시해둔 의문점에 대한 고찰


1. group by가 필터를 하는 역할 

2. group by 이후 users.id(users테이블의 id라는 필드) 제외하고 필터를 걸겠다.

3. select *이란 것은 users 테이블에 있는 모든 필드를 출력하겠다라는 의미 

4. if. select username from users where userid = ''group by users.id having 1=1-- 


스스로 가져본 의문 

해당 명령문의 결과(4)는 올바르게 도출 될 것인가 ? 혹은 그렇지 않을 것인가? 


생각해보았을 때 찾아야 하는 필드를 정확하게 명시하였고, group by로 필터 해둔 범위가 id필드 뿐임과 동시에 where userid라는 명령을 통해 users 테이블의 userid 필드만 검색하라고 했기에 로직 상 에러가 없다고 판단 되었음.

그러므로 select * vs having 1=1-- 둘 중 priority는 having 1=1--으로 판단 하였음.



추가적으로 알게 된 것 : Order of Statement Execution in SQL

[1] FROM

[2] ON

[3] OUTER

[4] WHERE

[5] GROUP BY

[6] CUBE | ROLLUP

[7] HAVING

[8] SELECT

[9] DISTINCT

[10] ORDER BY

[11] TOP



'0x09 WEB Hacking 기초공부' 카테고리의 다른 글

prob2 하기 전 공부한 것 2  (0) 2018.07.26
prob2  (0) 2018.07.26
prob2 하기 전 공부한 것  (0) 2018.07.26
prob1  (0) 2018.07.26
Webhacking.kr 회원가입  (0) 2018.07.25
0 Comments
댓글쓰기 폼