Google: Process Failure Modes
This is a modal window.
Das Video konnte nicht geladen werden, da entweder ein Server- oder Netzwerkfehler auftrat oder das Format nicht unterstützt wird.
Formale Metadaten
Titel |
| |
Serientitel | ||
Teil | 10 | |
Anzahl der Teile | 20 | |
Autor | ||
Lizenz | CC-Namensnennung 4.0 International: Sie dürfen das Werk bzw. den Inhalt zu jedem legalen Zweck nutzen, verändern und in unveränderter oder veränderter Form vervielfältigen, verbreiten und öffentlich zugänglich machen, sofern Sie den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen. | |
Identifikatoren | 10.5446/32743 (DOI) | |
Herausgeber | ||
Erscheinungsjahr | ||
Sprache |
Inhaltliche Metadaten
Fachgebiet | ||
Genre | ||
Abstract |
|
REcon 201610 / 20
3
5
6
9
10
13
15
17
20
00:00
MultiplikationsoperatorSystemaufrufATMBenutzeroberflächeBildschirmfensterQuick-SortProzess <Physik>Physikalisches SystemBitInformationProgrammfehlerIterationPunktElektronische PublikationFunktionalOrdnung <Mathematik>AdressraumGarbentheorieThermodynamischer ProzessQuaderCASE <Informatik>MAPHackerPhysikalische TheorieRechter WinkelKartesische KoordinatenPräprozessorMessage-PassingHochdruckDienst <Informatik>Minkowski-MetrikAggregatzustandExogene VariableLokales MinimumNabel <Mathematik>InstantiierungTopologieCodeMereologieRuhmasseSpeicherabzugThreadVirtuelle AdresseVirtualisierungApp <Programm>LastWort <Informatik>ParametersystemBildgebendes VerfahrenInzidenzalgebraKernel <Informatik>Token-RingJSONXMLUMLFlussdiagramm
05:26
GarbentheorieFahne <Mathematik>BildschirmfensterProzess <Physik>VererbungshierarchieParametersystemÄquivalenzklasseQuick-SortSoundverarbeitungFreewareATMBildgebendes VerfahrenPhysikalisches SystemAttributierte GrammatikDifferenteMailing-ListeAutomatische IndexierungQuaderHackerSystemverwaltungMechanismus-Design-TheorieElektronische PublikationCodeKernel <Informatik>Güte der AnpassungBitStapeldateiEmulatorDatenstrukturProgrammierumgebungZeiger <Informatik>EinsVersionsverwaltungOffene MengeRandwertRechter WinkelDienst <Informatik>Radikal <Mathematik>NetzbetriebssystemMereologieThermodynamischer ProzessEntscheidungstheorieKartesische KoordinatenSoftwareAusnahmebehandlungStellenringEindringerkennungIdentifizierbarkeitAdditionInteraktives FernsehenInformationSystemplattformVideokonferenzVektorpotenzialComputersicherheitsinc-FunktionDemo <Programm>KardinalzahlNormalvektorHalbleiterspeicherEinfügungsdämpfungIntegralFunktionalNeuroinformatikHypermediaMinimalgradDebuggingInhalt <Mathematik>Vorzeichen <Mathematik>KugelDefaultBenutzeroberflächeNichtlinearer OperatorUnendlichkeitGamecontrollerp-BlockGruppenoperationPhysikalische TheorieAuthentifikationWellenpaketSystemaufrufE-MailComputeranimation
14:35
EinsPhysikalisches SystemProzess <Physik>StellenringThermodynamischer ProzessBitKlasse <Mathematik>PasswortElektronische PublikationZeichenketteDynamisches SystemAnalysisQuick-SortProgrammfehlerRechter WinkelBildschirmfensterToken-RingSoftwareschwachstelleIdentitätsverwaltungNichtlinearer OperatorComputersicherheitDienst <Informatik>PunktTaskGüte der AnpassungKartesische KoordinatenLimesmengeSoftwareFaserbündelSchedulingProgrammierungVererbungshierarchieCodeDemo <Programm>Mailing-ListeGamecontrollerInformationHyperbelverfahrenRandwertCASE <Informatik>HalbleiterspeicherGarbentheorieVorzeichen <Mathematik>Primitive <Informatik>Reverse EngineeringGruppenoperationBenutzeroberflächeMultiplikationsoperatorExogene VariableDefaultLie-GruppeMAPMereologieGemeinsamer SpeicherHilfesystemObjekt <Kategorie>RechenwerkMessage-PassingSystemaufrufPhysikalische TheorieFontComputeranimation
24:18
Prozess <Physik>Dienst <Informatik>HoaxPhysikalisches SystemMAPToken-RingVerschlingungOffene MengeEinsNormalvektorVerzeichnisdienstVererbungshierarchieElektronische PublikationFlächentheorieStrömungsrichtungURLZahlenbereichKategorie <Mathematik>Schreiben <Datenverarbeitung>Diagramm
25:54
Prozess <Physik>HypermediaFunktionalElektronische PublikationProxy ServerKlasse <Mathematik>VirtualisierungObjekt <Kategorie>ProgrammfehlerPräprozessorNabel <Mathematik>Physikalisches SystemDienst <Informatik>SystemaufrufClientTypentheorieCholesky-VerfahrenThermodynamischer ProzessToken-RingProgrammbibliothekQuick-SortDampfTermVirtuelle MaschineGesetz <Physik>CASE <Informatik>KonfigurationsdatenbankGruppenoperationt-TestQuellcodeInhalt <Mathematik>MereologieMAPSystemverwaltungSoftwareschwachstelleExistenzsatzIntegralComputeranimation
30:17
Prozess <Physik>Token-RingComputersicherheitResultanteElektronische PublikationOrdnung <Mathematik>Kartesische KoordinatenRechenschieberParametersystemGarbentheorieTask
32:06
AbfrageProzess <Physik>VerzeichnisdienstPunktObjekt <Kategorie>ComputerspielMultiplikationsoperatorThermodynamischer ProzessPhysikalisches SystemAggregatzustandDienst <Informatik>Kernel <Informatik>Affiner RaumQuick-SortTypentheorieRadikal <Mathematik>DefaultSymboltabelleDatenstrukturGarbentheorieSystem FNamensraumZahlenbereichDatenverwaltungProgrammfehlerBitNichtlinearer OperatorVerschlingungPerspektiveCodeZeiger <Informatik>AnalysisDynamisches SystemBildschirmfensterGruppenoperationToken-RingElektronische PublikationOrdnung <Mathematik>BenutzeroberflächeComputersicherheitStrömungsrichtungCodierungZählenThreadRichtungArithmetisches MittelLastDiagrammFlussdiagramm
38:00
KonfigurationsraumTotal <Mathematik>Prozess <Physik>PunktgitterBitHalbleiterspeicherVerkehrsinformationProgrammfehlerObjekt <Kategorie>Mailing-ListeRichtungDreiecksfreier GraphKernel <Informatik>ComputerspielGüte der AnpassungKartesische KoordinatenPhysikalisches SystemQuick-SortWiderspruchsfreiheitThermodynamischer ProzessGruppenoperationDifferenteToken-RingSystemaufrufRadikal <Mathematik>App <Programm>FunktionalWeb logThreadVerzeichnisdienstEreignisdatenanalyseObjektorientierte ProgrammierspracheComputeranimation
40:28
Prozess <Physik>Quick-SortServerAggregatzustandRadikal <Mathematik>Dreiecksfreier GraphMereologieSystemverwaltungToken-RingDiagrammInteraktives FernsehenTypentheorieThermodynamischer ProzessTerm
42:24
SystemaufrufDemo <Programm>Prozess <Physik>Walther-Meissner-Institut für TieftemperaturforschungWeb logThermodynamischer ProzessProgrammfehlerBitDatenstrukturAbzählenParametersystemExistenzsatzCodeGarbentheorieObjekt <Kategorie>Elektronische PublikationInzidenzalgebraMailing-ListeExogene VariableBildgebendes VerfahrenBeweistheorieInformationSichtenkonzeptQuaderp-adische ZahlHackerAbfrageHochdruckDifferenteProzessfähigkeit <Qualitätsmanagement>Kartesische KoordinatenComputerspielComputeranimation
45:39
BildschirmfensterProzess <Physik>Walther-Meissner-Institut für TieftemperaturforschungHackerBinärdatenFaltung <Mathematik>DatenverwaltungHilfesystemElektronische PublikationATMDateiverwaltungPunktRechter WinkelAbzählenAdditionLesen <Datenverarbeitung>Demo <Programm>BildschirmsymbolOffice-PaketWeg <Topologie>QuantenzustandBildgebendes VerfahrenMereologieTaskMailing-ListeProgrammierumgebungRPCQuick-SortObjektorientierte ProgrammierspracheArray <Informatik>Computeranimation
48:26
GarbentheorieBildgebendes VerfahrenElektronische PublikationProzess <Physik>Schreiben <Datenverarbeitung>System FGemeinsamer SpeicherHalbleiterspeicherWort <Informatik>Kartesische KoordinatenComputeranimation
49:16
GarbentheorieHalbleiterspeicherZeichenketteHackerBildgebendes VerfahrenElektronische PublikationComputeranimation
50:04
GeradeElektronische PublikationPhysikalische TheorieTreiber <Programm>PunktProzess <Physik>Bildgebendes VerfahrenAbgeschlossene MengePhysikalisches SystemGarbentheorieNichtlinearer OperatorTopologieEinsGanze FunktionBitComputeranimation
52:04
Inverter <Schaltung>BenutzeroberflächeElektronische PublikationQuick-SortSpielkonsoleKartesische KoordinatenProzess <Physik>Filesharing-SystemThermodynamischer ProzessProgrammierungKernel <Informatik>CASE <Informatik>PunktBildschirmsymbolGewicht <Ausgleichsrechnung>IntegralDiagramm
53:42
Demo <Programm>CASE <Informatik>Prozess <Physik>Elektronische PublikationAbgeschlossene MengeComputeranimation
54:31
MultiplikationsoperatorRechter WinkelGüte der AnpassungDivergente ReiheCoxeter-GruppeProgrammbibliothekFunktionalTermSoundverarbeitungDynamisches SystemBestimmtheitsmaßElektronische PublikationComputeranimationXML
55:29
Prozess <Physik>InformationFahne <Mathematik>Elektronische PublikationBitVerdeckungsrechnungThermodynamischer ProzessDemo <Programm>CASE <Informatik>LastBenutzeroberflächeComputeranimation
56:37
ATMLastOvalVollständigkeitSoftwaretestBitElektronische PublikationZeichenvorratOrdnung <Mathematik>Computeranimation
57:27
Radikal <Mathematik>Dreiecksfreier GraphProgrammfehlerThermodynamischer ProzessProzess <Physik>Dienst <Informatik>BitBrennen <Datenverarbeitung>MultiplikationsoperatorExogene VariableZählenSystemverwaltungMechanismus-Design-TheorieInzidenzalgebraServerMotion CapturingComputeranimation
59:08
Computeranimation
Transkript: Englisch(automatisch erzeugt)
00:27
So, hi, good afternoon, Recon. I'm Robert, and so I'm going to be talking about Windows processes,
00:45
and the usual ways in which creating processes can really screw you up sometimes. So, specifically, I'm going to start talking about Windows creation APIs, so process creation APIs.
01:00
And a bit of the low-level stuff regarding that, I'm not going to go down to the level of like the individual creation of virtual address information and things like that, but the sort of more top-level information you may find interesting. Then I'm going to talk about some classic bugs, which I've discovered over the years in code which creates processes,
01:22
or code which handles processes which you can then abuse to do things like privilege escalation. Hopefully, if I've then got some time, I'm going to go through some sort of silly tricks that, if you are feeling particularly mean to the incident responder, you can confuse them and give them a heart attack.
01:41
And this is all based on Windows 10 stuff, and I thought it was worth pointing out, I'm not going to talk about like spaces in unquoted command line paths, or anything like that, so you're sorted on that one. I'd like to thank Alex and MJ32 who writes like Process Hacker.
02:00
They've done obviously research on this side as well, and they are very knowledgeable in sort of process-related internals. Process creation APIs. So, it's a bit of a mess. If you look at it from the user level, the user API level, it's all over the place. As you can see, I've drawn quite a few boxes in here.
02:23
Anything in blue is stuff which a user application could call. So these are sort of directly documented interfaces. For example, there is the function winexec, and winexec is a holdover from 16-bit Windows, is how on 16-bit Windows you create new processes.
02:42
These days, it's there for maintaining compatibility with lazy shellcode writers, because there's too many parameters to create a process, so I'm just going to use winexec. There's other stuff like shell execute, which is actually part of the shell itself, and this is more for generic. I want to create something which handles a doc file,
03:02
so I tell shell execute to run .doc, and it will load Word for me. But you can also use it to run executable files as well. But they both sort of funnel down to create process, which is a sort of main entry point in win32 API to actually do process creation. Then there's other stuff.
03:22
There's various services which will get involved if you call certain things. For example, the UAC, or app info service, is responsible for elevating processes on Vista and above. If you call shell execute, it will automatically sort of feed off to that app info service, but there is no documented interface to calling that, other than via shell execute.
03:42
And then there's things like the secondary logon service, we're using create process with token. But all that taken into account, everything then feeds down into one function, create process internal, and then eventually ends up at NTDLL, which ends up at the Windows kernel itself.
04:00
Now, if you come from a Unix background and know how processes are created in Unix, you'd think it would be really, really simple, like why would anyone design a really complicated process of creating new processes? Of course, obviously, NT didn't take that approach, as probably is fairly common. So, in the beginning, and this is sort of pre-Vista,
04:23
what you had is a system call called NT create process. So you think, okay, it's creating a process, must be simple. Pass it in the name of a file, it runs it, job done. Obviously, I wouldn't be describing this if that wasn't actually the case. So instead, what actually happens is it first opens the file,
04:41
and this is all happening in user mode, calls a system call, opens me a file, gets back a file handle. It then goes, okay, that file handle needs to be a memory map section, so I'm going to call NT create section with the file handle, get back an image section. Finally, finally, we call the NT create process, passing our image section to it,
05:01
and it creates our new process for us. Awesome, job done. We've got a running process, but we haven't. All we've got is a process. We still need to create a thread in that process, and, finally now, in theory, we should be able to execute code. So, it's obviously a simple process of four or more steps
05:20
to create a basic process. How could that possibly go wrong? Now, the actual API itself is relatively simple. There's only sort of three parameters that you really care about. You can get a Windows handle to the parent process. There's some flags which just basically change
05:42
the way in which the process is created, and then your section handle. But, interestingly, the section handle is optional. You don't have to actually specify a new section for your new process. So, what happens if you don't specify it? Well, effectively, what you get is fork. You get your Windows equivalent of fork.
06:00
It doesn't work very well, but it is actually there, and it was built in from day one into Windows. It's not really very well exposed from the APIs. But this brought a problem. In Microsoft's infinite wisdom, they thought, well, if we don't do something about these horrible hackers
06:21
trying to steal protected content, no one's going to want to run videos, commercial videos or commercial audio on the Windows platform. So, we need some way of stopping those nasty, nasty hackers. And we can't even trust that nasty hacker to not be an administrator on their own box because the majority of consumers of Windows
06:41
are probably admin already. So, they came up with the wheeze of protected processes, which sounds all grandiose, but actually wasn't actually quite that useful because all it did was protect against user mode. It didn't protect against kernel mode. But I left them with a problem. How do we create a process in user mode which required all these various steps to succeed
07:03
without betraying and without leaking the access to this process? So, in Vista, they created the nt-create-user-process system call, which, instead of requiring you to do all these intermediate steps in user mode, did it all in the kernel for you. And this all makes it much simpler, much easier.
07:26
Now, unsurprisingly, nt-create-user-process has one or two more parameters you need to pass. The main ones are the three at the end. The three at the end, the first one is something called the user process parameters.
07:40
And, effectively, these are ignored by the kernel, more or less. They have to inspect them and make sure they're valid, but they don't actually do a lot with them. Effectively, all they do, they inject them into the new process, attach a pointer to them from the process environment block, the PEB structure in the new process, and then that process can refer to them. So, things like the command line,
08:01
obviously, you pass the command line in this block, and that command line can be read out by the internal process, which knows about the structure of the PEB. The next one is the create infrastructure, and this contains sort of the basic sort of information about what you're wanting to create. It has some flags, has some additional sort of features,
08:22
and what effectively comes back is all the stuff which you kind of used to get in the good old days of nt-create-process, things like a handle to a file and a handle to a section, without actually having to do that in user mode itself. And so it sort of gives you back some interesting information, which we'll see later.
08:42
Couldn't be kind of amusing. And the final thing is basically the mechanism for which you extend this function. Rather than having nt-create-user-process-exex20 or whatever, Microsoft decided to basically have a list of arbitrary attributes you can specify.
09:02
So, for example, you can say, I want to create this process with a different parent process, or you have to specify the image name, and the image name is the path to the file you want to open. So this can be extended as you go along, so, for example, the latest version of Windows 10 has more of these attributes,
09:21
and so if you don't have to change the interface, they can just add these extra attributes on top. But to paraphrase Monty Python, what has create-process-internal now does for us? Why is it even there anymore? Well, unfortunately, Win32 is not kind of as simple as the kernel layer allows.
09:41
You've got to do various different things to actually support what Win32 behaviors are expected of create-process. So things like you need to register the side-by-side manifest with CSRSS. Why? Who knows? But you have to, and if you don't do so, creating processes like notepad.exe will tend to fail
10:00
and give you horrible, scary warnings. It also does stuff like, if you pass it a batch file, it has to emulate that, oh, I'm actually going to run command.exe on this batch file instead of trying to just execute it directly. So the kernel doesn't realise how to execute batch files, but create-process-internal knows how to do that.
10:21
And also, if you've ever encountered software restriction policy, this is where software restriction policy is enforced. Note, this is not AppLocker. This is the old XP user-mode application restriction policy technology, which, again, I'll show an interesting consequence of that decision.
10:45
Now, each process runs in what is called a session. So, not each process, each user, when you log into a system, is assigned some sort of session, which is identified using a numeric identifier, literally just like 0, 1, 2, blah.
11:01
And all those user processes run within that session, and this is sort of like an isolation boundary between different parts of the operating system. And it's basically to allow things like the windowing system to display a window, but not allow you to interact with the windowing system of another user on the same box. Especially on terminal services, this is quite important. Now, since Vista, on XP, you used to log in to the front end,
11:23
and it would give you session 0. And session 0 had a few benefits of being session 0, which had potential security complications. So, in Vista, a normal user cannot log in to session 0, or at least directly can log in to session 0. That's reserved purely for services,
11:40
and everything else is given a numeric identifier on top of that. And we can set the session ID, but kind of, at least in default, only if you're running as local system. If you're running as the TCB, have TCB privilege, or the trusted computing-based privilege, only then can you set one of these session IDs and effectively create a new session
12:02
and run something in a different session. But there are some exceptions to that, and I'll show some examples of this as we go along. But basically, if you have certain access to certain processes, you can actually circumvent this TCB requirement. Now, sort of, it's somewhat different from other operating systems.
12:24
You can say explicitly what process is your parent. This was, again, sort of added to support user account control, UAC, because when you created a privileged process, you kind of want it to sort of run underneath the process which asks for it to be created.
12:41
But, of course, it's a separate service which is doing it, so in theory, it would be parented by that service, and you may not want that to happen. So, Windows now allows you to specify an explicit parent, but you need a certain access right, and this access right is basically sort of a right privilege, and if you have right privilege to a process,
13:00
you can modify virtual memory, all that sort of stuff. So, normally, users invariably can't access this and use this to their advantage, but other parts of the operating system can, and I'll show an example now. So, as I go along, I've got a few demos I can show, and one common thing people will do,
13:20
they'll want a process running as local system, because local system has more privileges, but they also want an interactive process and all that sort of stuff, and generally, like the way you do that, is you download PS exec off the internet and run that with minus S, minus I,
13:41
and it creates you an interactive system process. It installs a service, all this sort of good stuff. Obviously, it leaves a bit of a trace and a bit of an obvious like you're trying to spawn a system process. But as long as you're an administrator, you can actually open a system process, specify it as your parent, and it will create you an interactive system process on your desktop
14:03
that you can actually play with. So, I've got just a simple, if I can actually see my, so, I've written up some basic APIs to play with in PowerShell. Hopefully, I can release these fairly soon after the conference,
14:21
once I've cleaned them up a bit and removed some of the terrible code in it. But all this does is it will spawn a process using this, and it will look for, specifically, search indexer.exe, and search indexer.exe is this one, so it's running as local system.
14:41
So, hopefully, if I run this, we should have, okay, so we've got a process, and we can look at that, and we should have demo.exe running as local system, and it's obviously interactive because we can see it on our desktop. And so, that's a really easy way. You can do that using crate process as user,
15:02
or the crate process API directly in simple bits of code, probably, say, from VBA, you can do that if you wanted to. So, now, each process has an identity of some kind,
15:20
and its identity is defined by its process token. Or, basically, the token contains things like your groups, your user identity, what privileges you have, et cetera. Now, when you create a new process, you can, in theory, specify a new token. By default, it will inherit the token, as we saw, from the parent. If the parent is local system,
15:42
then the new process will be local system. You can specify an explicit one. Now, unless you have privilege to do so, you've actually got only a limited set of tokens you can assign, and that's related to its parent or sibling token relationship. And if you don't have that relationship, you can't assign it if you have no privilege.
16:01
So, this allows you to do things like sandbox creations. You can create a restricted process, but you can't create a system process just because you've got access to a token. We can go back to sort of CSRSS and the pain that causes. CSRSS shouldn't be, for the most part,
16:22
you can run a process on Windows without requiring CSRSS at all. But so many of the Win32 APIs rely on CSRSS being up and being initialized that, basically, you can't really get by without it, which is kind of a shame. Now, fortunately, if you're just playing with the low-level APIs, you can actually create a process,
16:42
and as long as it doesn't require a side-by-side manifest, it will generally work. That demo I just had is a really, really simple Win32 process, but I've not actually registered a side-by-side assembly, because that's a lot of extra complication to add to the code. So instead, it creates it,
17:00
but fortunately, the new process will register itself with CSRSS, which is kind of important. We'll see a bug in that in a little bit. Okay, so again, if you come from the Unix world, you probably are accustomed to inheritance of file descriptors. Whenever you fork a process, your file descriptors, by default,
17:21
will be inherited across that process boundary. Now, in Windows, that's not the case. In Windows, you have to explicitly say, I want to inherit handles from one process to another, and not only that, when you do so, you need to mark each handle you want to inherit, explicitly saying, this handle is inheritable.
17:42
Now, of course, this actually causes some interesting problems, which they tried to solve using a handle list, so now you can specify exactly what handles you want to inherit, but you can still only inherit handles which are marked inheritable, and you also still have to specify the handle parameter, which is a bit of a pain.
18:01
Okay, so those are sort of the bits of the background of the APIs, which would be important for the sort of later information I'm going to present. So what this bit now is talking about bug classes you can find in Windows. Hopefully, there's not too many of them. If I've not cleared them all out,
18:20
then obviously I'm not doing a very good job. But these are typical classes of bugs you can find, which are related to process handling, which you can then potentially use to do elevation of privilege, and you can find them, and if you look for reverse engineering, stick them in IDA, or do some basic sort of dynamic analysis of the system, you hopefully can find these bugs.
18:44
And the first few are related very specifically to privilege process creation, not necessarily creating privileged processes, but having a privileged service, which on your behalf is creating new processes. So a good example, for example, is the task scheduler.
19:01
The task scheduler, you specify a program you want to run at a certain time, but the task scheduler runs at system. It runs in a privileged account. So it needs to create that process for you at some later date, but it needs to do it securely. It can't spawn at a system, because if it spawns at a system,
19:20
well, you've just got a trivial privilege escalation. So it needs to create it as a normal user, and it needs to do that in a secure way, because if it mishandles the APIs, there could be a security issue associated with that. So I don't know whether this is actually documented by Microsoft anywhere,
19:40
but there is kind of a canonical, safe way of creating processes. And this is basically what you're supposed to do. Say, for example, the user requests a service to create a process for you, but wants it to be done under its own user identity. You first need to get an impersonation token for that user,
20:01
and that could come from RPC, it could come from name pipes, it depends on how you're calling the user. It then is supposed to impersonate that user so that any subsequent access can only run with the rights of that user. You finally then call createProcessesUser, which is the Win32 API to specify an explicit token,
20:22
passing the token you want to create it under, while still impersonating the user. And that's very, very important, because if you don't, bad things can happen. Because if you look at how the underlying APIs create processes, when it opens a file, it first goes, okay, I need to open this file,
20:42
I'm going to make sure that I force an access check, I'm going to make sure that this user is allowed to open this file. If it's not allowed to open this file, obviously, access denied, getStuffed, go away. But of course, there's no impersonation at this point. The token you've passed as the primary process token
21:02
is not referenced in any way during this operation. So the only person, the only identity this will get run under is the caller's identity, which if it's a system service is the system process, the system user, which means you could potentially open files you're not supposed to be able to access.
21:22
So the first sort of bug is this one. So if you find a piece of code which creates a user process but forgets to impersonate the user while doing so, you can basically access files that you shouldn't be allowed to access. And I've got obviously an example here, issue 161,
21:41
so it's quite an old issue. The task scheduler on Windows 8 forgot to do this, and basically allowed you to spawn arbitrary processes even though you couldn't access the XE file itself. So you could bypass the access control list on the XE file and create a new process with that user. And because of the way the create process works,
22:02
once you've opened that file, it doesn't matter that the user can't directly access that file at all because it's already spawned the process and mapped in the section, mapped in the memory, so you can access whatever's in there. So this is obviously, potentially you could find interesting things if a process has embedded strings or embedded passwords
22:22
which normally would be ackled away. You could get this and open it and extract that data. But as an added bonus, because you're running this as system, even though it's created as a normal user, it actually bypasses the software restriction policy. Unfortunately, it doesn't seem to bypass AppLocker because of the way AppLocker works,
22:40
but it does bypass the old XP-style software restriction policy. So if you find a bug like that and you encounter some application which actually they're deploying SRP, you can basically use that to bypass it. Now, looking at it from a different way, what if you're impersonating a user
23:01
but something creates a privileged process while doing so? Now, talking about the previous bug, you may not think that's actually an issue. The worst-case scenario is it may fail to access an executable file it would normally have expected to access.
23:21
And bear in mind, this createProcess call doesn't have to be explicit. It could be something buried deep down in the API somewhere. It calls an API which eventually spawns a helper process, not actually taking into account that somewhere higher up it's actually impersonating this user. But it does have an interesting security issue.
23:43
Namely that the create process operation, the createFile operation which happens in NTCreateUserProcess, does not take into account that an impersonated user can redirect the C drive somewhere else. So if you try and create something under the C drive, for example,
24:02
if you're impersonating a user and something doesn't specify this extra file attribute, which is actually added because I pointed out you could use to be able to do this with DLLs, and that was obviously a considerably more serious vulnerability than this one. But because it doesn't do this, you can redirect the C drive. So you can do basically something like this.
24:20
You find your privilege service which does something, I don't care what, just does something. It doesn't even have to be create me a process. It could be completely unrelated. But all you know is it's going to create a privilege process while impersonating our current user. That privilege service impersonates us and then calls createPrivilegeProcess.
24:41
Now, before we did this, we added a link to our device map which said the C drive for us, personally, is this arbitrary location over here. It's fake directory number one. So it's completely unrelated to the normal C drive. CreateUserProcess goes, okay,
25:02
I will call zwopenfile. I want to open C colon slash some file, for example. So it opens it. But because we're impersonating, it actually redirects that access request to somewhere else under the user's control. Now, it's kind of important to note that
25:21
when you create a process while impersonating, it doesn't inherit the impersonation token. Instead, it still is whatever the parent token is. So if it's coming from a system process, you could be impersonating JoeBlogs and it will still create a system process unless explicitly you tell it not to. So obviously, what happens,
25:42
we've pointed it to malicious.exe and bang, all of a sudden, we've got a privilege process running because we've redirected the executable access to somewhere else. So can you find any scenarios in which this actually occurs? Well, back in 2014, there was a bug
26:02
which admittedly I didn't find. I'm not going to claim credit for that one. But it was a bug in shell execute. Specifically, it was a bug in the way shell execute handled .exe file content while running its system. And what you could do, if you're impersonating a user and call shell execute, you could basically cause .exe files
26:21
to be redirected anywhere you liked. And Microsoft fixed this, although I've yet to ever be able to track down exactly what system service this was, which was being abused. Perhaps it was a third-party library which was causing it to cause problems. But you can definitely find it. If you find anything calling shell execute while impersonating the user in a system service,
26:43
that is automatically vulnerable to these issues. So we can kind of take a step back and think about, OK, we've got two types of bug classes. Is there actually a more general bug class related to that? And it turns out sort of there is.
27:02
In fact, the bug class is, are you impersonating a user which doesn't match up with the token you're going to create that process under? And this sort of mismatched impersonation obviously can be specified into those other two bug classes, but this is sort of the general case.
27:23
So it is possible to find bugs which actually exploit this particular scenario as well, actually like this whole, I'm impersonating one user while doing something else with a different user. And you can go and look up issue 692, which is a bug I found in CSRSS.
27:42
Absensibly it was there to help the user in some way, but ultimately it then led itself to sort of a privilege escalation vulnerability. And it related to a system service. So in CSRSS you have an RPC server, and there was a RPC call called base serve check VDM.
28:01
And the purpose of this function was to check whether the virtual DOS machine was installed and enabled. I'm not sure why CSRSS had to do this, but CSRSS apparently had to do this. So it checked the registry and said, okay, the DOS VDM is not installed. I could just fail, but that was not particularly nice.
28:22
So instead, I'm going to be really helpful. I'm going to create a new process on the user's desktop which says, hey, you may want to install the VDM or get the administrator to install the VDM. And therein lied the problem. Because this call, basically what it did, it first impersonated the client to the call
28:43
and said, okay, I'm going to take your impersonation token and use that as the token I'm going to create the new process under. It then did the right thing. It impersonates the client process over the call to create your process as user.
29:00
Surely, that shouldn't be a problem. Well, instead of impersonating the token it already had, instead, it opens the calling process object itself, extracted its primary token and used that as the impersonation token. And it just so turns out that the user you're calling CSRSS as
29:21
does not in any way have to match the primary token you're running your process under. So the thing I use to abuse this is something called the anonymous token. And the anonymous token is a built-in token you can get calling NT impersonate anonymous user.
29:42
And everyone can do it. Everyone can use this. And for the most part, it's utterly useless. The token itself is totally, totally uninteresting whatsoever. You have no groups. Your integrity level is basically fuck all. And effectively, you can do nothing with it
30:01
for all intents and purposes. But crucially, what it does have, it has its session ID set to zero. And that kind of is interesting, because if I can create a process in session zero, maybe I can do something more interesting. So what happens is basically this. Our user in session X calls base serve check VDM.
30:25
That calls into CSRSS. And we do this while impersonating the anonymous token. There's basically no security in stopping you from doing this. You can impersonate the anonymous token. It goes to CSRSS. CSRSS goes, cool, I'll use the anonymous token as my primary token.
30:41
It then opens the user's process, takes its process token, and impersonates the user. And this is actually crucial, because as the anonymous token has zero rights, basically, if it didn't do this, you couldn't even access the .exe file in order to spawn the process in the first place if it was impersonating the anonymous token.
31:02
So by mismatching the impersonation token to the primary token, we can use the user to open the .exe file and then assign anonymous token as our primary token. And the ultimate result of that is we've got a new process running in session zero,
31:20
because it has no better argument for it, running as the anonymous user. But so what? This is the anonymous user. You've still got focal access. You had focal access before. Now you've even got less access. So, what do we do? Well, as long as we stop that process from starting, we can use the API to set a new process token.
31:43
And one of the things I pointed out in the earlier slide is if you set a token to a process in a different session, that token automatically has its session ID set to the target process. So now we've got a session zero application running as a normal user, and we can do some fun stuff.
32:03
Okay. So what fun stuff could we do? Well, okay, fun may be the wrong word for this. I think you have to be a long-time Windows researcher to get excited about session zero access. Basically, one of the interesting things you can do,
32:21
session zero is given a special place, basically. Whenever you create a named object in session zero, it's put under a slash-based named objects directory in the object manager namespace. Now, there's a problem with that in that system services also use that
32:41
because they're also running in session zero, and that would be a problem. So what happens is anything which isn't session zero is not allowed to create two crucial types of objects inside that directory. You can't create section objects, and it can't create symbolic link objects because otherwise you could do some fun stuff and basically name squat on system service resources.
33:04
So you could create a service which may try and access a section, do some fun stuff with it, and you've already sat there with the name and redirected it to your own server so that you can open it with your own privilege. But fortunately, if you're running in session zero, you can do all the name squatting you like.
33:21
You can squat everywhere and use that to basically abuse existing system services, especially now since Vista, because system services don't even expect that this can even happen anymore. It shouldn't even be possible for a normal user to abuse session zero anymore. So all these bugs you can find if you stick it in IDA,
33:42
if you're so inclined. But the trouble with this is a lot of it relies on the sort of current state of the operation, who's impersonating what. And actually to do that is really more of a dynamic analysis kind of thing. So one of the best ways I do is just use process monitor. Just use process monitor,
34:01
look for anything where it's opening a file for execute access because that's kind of a rare thing to do. Most of the time, files are not directly open for execute access unless they're DLLs, and you can obviously limit it to .exe files and be sure that it will actually work. And obviously, it has a section of its details
34:20
which says whether it's impersonating or not. So doing a simple filter like this, you can see any operation which either is impersonating and creating a process or not impersonating and creating a process. It's also worth pointing out, you can also look for things which, with the mismatched creation, obviously you're looking for, say, something impersonating system or some other user and creating it with a different user.
34:42
And unfortunately, that's not quite as easy to see from process monitor. But with a bit of playing around, you can see it. So those were bugs where they're sort of manifest because of incorrect coding in privileged services and doing stuff on the user's behalf.
35:01
Because unfortunately, there's no easy way of... As I say, I'm not even sure it's necessarily documented. You must do this, otherwise potentially there's a security issue. There could be somewhere. I'm sure probably Alex will know where that may be documented. But this is a bug more in how Windows actually works
35:22
and how Windows handles kernel objects and handles processes. So when you create a process, your process ends up effectively in an initialised state of some kind. It's currently not running. It's not actually initialised itself. Most of its DLLs haven't been loaded yet. But when you first start the initial thread,
35:42
it will transition into a running state and it will start doing its initialisation, start running. You can then, while it's active, you can go from running to suspended and vice versa. Like if you're debugging, whenever you break point on a thread, it may shut all the other threads down, suspending the process. Then finally, obviously the process exits or explicitly is terminated
36:02
and it ends up in a terminated state. Very simple. Now, underneath the hood, a process has a kernel object, an e-process structure which represents what that process actually does. And kernel objects are lazily deleted. Effectively, they're reference-counted objects
36:20
and until all the references go away, it will maintain that object indefinitely. Now, there's actually two reference counts. There's the kernel object reference count. This is a kernel. The kernel can access the pointer and just increment the reference count directly. But also, user-mode code can get a handle to that process
36:40
which also has an implicit reference count associated with it. So until both of those values go to zero, that process will stick around forever. Now, actually, a process isn't an isolated object. It has references to other objects. And you can see various different things here. You've got things like the section object and the file object.
37:00
This references to the file section that it was created from. It has a token object. But then, at the other side, there's loads of threads which potentially run inside that process. And they also reference the e-process structure. And this has become quite important because when you terminate a process, by default, what happens is everything goes away except for the process structure and the token structure.
37:24
Everything else gets dereferenced. That doesn't mean it goes away, but everything else gets dereferenced. So if you maintain a handle to a process after it's terminated, that process still sticks around. And that's intentional. The reason for that, for example, if I want to know the exit status of a process,
37:43
well, how am I going to find the exit status of a process if the kernel has deleted the process object after it's terminated? So as long as you've got a handle to it, you can still query the exit status. And you can actually find on most systems a number of terminated processes which is just sort of sitting around doing nothing.
38:01
Oops. Hopefully it's not. All right. Run that. So on here, for example, I have three processes which have just sort of exited, but something is maintaining a reference to them. You can't see them necessarily. And they're maintaining a reference to them,
38:20
but if you go and look at the list of processes, you probably won't find these processes in the list. They're kind of hidden from the system because they don't run anymore, but they are still around. The kernel objects still sit there in memory and can be interacted with. Now, accessing my own process isn't actually that interesting.
38:44
But one interesting scenario is what if a terminated process from me was in a different session and it's gone, but something kept it lying around so that we can open it to a later date? Would that be interesting? Of course, because I've got a bug report about it.
39:02
This is a bug which basically allowed you to... You can read up a bit more about it. There's a blog post about it. But basically, the ntcreate-lowbox-token function, which is used to create tokens for app container applications, took a list of handles. And this is ostensibly for maintaining all your app container-specific configuration,
39:22
object directories and things like that. But it never checked what handles you were passing. So, for example, you could pass it a thread handle, and it would take a reference to the thread handle, and the reference would be maintained as long as the token survived. So you could do something like this. I can create a token object
39:40
which references an existing thread. And now the token object holds a hard reference to my e-thread object. I can then assign that token as an impersonation token to the thread. And now the thread maintains a hard reference to my token object. And obviously, that's a reference cycle.
40:00
And there's no way of breaking that reference cycle other than disassociating the token. Now, because my thread is maintained, it maintains the process. And the process maintains its token object. And this is unkillable. It's already dead. It's terminated. But there's pretty much nothing you can do about it.
40:22
It's just sitting there in memory, stuck, because there's a reference cycle you can't break. So you can do something like this. Say, for example, I log into a terminal server, and I'm running in session Z. I do my reference cycle trick, and I log out.
40:41
And that kills every process, but it doesn't actually kill my process. It sort of sits there forever, like in an undead state. I can then log back in, and because I own that process, I can reopen it as much as I like. If I reopen that process, I get back a process token with session Z.
41:01
Now, normally, I would not be allowed to set session Z explicitly, but I can get a use-after-free, actually, associated with that token. So I do that. I clear up the reference cycle so that the session can go away. And you end up now with a nice, unused, pristine session, just waiting, waiting for someone else to log in. Hopefully, like an admin,
41:20
you talk to your tech support, hey, I've got a problem with the terminal server. Can you just log in, please? Like, do something. Whatever. So you wait for the other user. You can then impersonate that user token, because the diagram I showed before with process tokens isn't the same as impersonation tokens.
41:41
I can impersonate another token quite happily, as long as it's me. And I can impersonate me. It's fairly easy to impersonate yourself, usually. It then... We then impersonate ourselves,
42:00
and what that does is it creates a new process running in session Z, because Win32 process never bothered to check that it shouldn't create something in a different session. It just blindly trusted you that, hey, you've given me this impersonation token. I assume you're in session Z. I'm going to create your process in session Z for you. At which point, you can start interacting with parts of this admin session
42:22
and start doing nasty things to them. Okay. So you can see, if you look at some of the bugs and that, there's obviously a bit more information around them, proof of concepts, you can play with that. There's various blog posts about this. But I thought maybe I should do something a little bit different to a lot of my usual bug talks.
42:41
Like, let's... Taking into account what the create process APIs do, can I just be a bastard to incident responders in some way? Is the things I can do a low-level trick that if they come and try and inspect my machine, either get the wrong answer, or they find that the process they were looking at
43:03
is in another castle or something like that. So, let's start off with fooling WMI, and WMI seems to have had a resurgence of late. I don't know if that's because PowerShell makes it really easy to interact with WMI or not. But WMI, it seems to be like these days the go-to thing,
43:22
like, I'm going to inspect this remote system, I want to know what processes are running on it, okay, I can enumerate processes over WMI, job done. Like, that gives me... There's no malicious process in that box. Awesome. Like, no problems there. So it would be kind of interesting if we could hide processes from WMI.
43:41
Now, unfortunately, I haven't found a way of hiding processes, but I can trick WMI in such a way that it thinks my process is a completely different process. And to understand why that happens, we just have to look at WMI itself. Now, most...
44:00
If you run, say, Process Hacker, and it gives you the list of executables running, and it will tell you, say, Notepad is running, and what it will do is to find that out, invariably, it will open the process and use an API call to get back the file name for that process. And that will tell you exactly what it is, because it's based on the file object and the section object,
44:23
which it was created with. WMI doesn't do that. I don't know whether it's because WMI, when this code was written, maybe that API wasn't reliable or didn't exist. It's definitely possible. So it takes a different tact. Instead, it reaches into the process and starts reading out data
44:41
out of our user process parameter structure. Now, the user process parameter structure, as I showed near the start, is just copied verbatim into new processes. And in fact, even an existing process can modify its own user process parameters. So what we can do, we can specify an arbitrary image path
45:01
and completely confuse WMI into where actually our code is running from. So obviously, a quick demo. So we've got trick WMI. I'm going to run a demo application, and I'll print out the process name, which will prove that I've created it under a different process.
45:23
And then I'll run a simple WMI query, which will actually return me back the assumed executable path for that executable. So we run that. So we have a process. And if we look here...
45:40
So we've opened slash bin slash notepad, which obviously is not C Windows Notepad. But as far as WMI is concerned, we're running C Windows Notepad. And now process hacker isn't fooled. You can see, hopefully, if I can find it, notepad.
46:00
Process hacker is quite happy to say that's the correct place. If you run that wonderful tool, process explorer, you'll find, as you can see, it definitely thinks it's notepad. It even gives you the icon. So you don't even have to trick the icon if you're feeling that lazy. And things like process monitor also uses WMI
46:22
to do the initial enumeration of file names. This is kind of interesting. Okay, so we're obviously assuming at that point someone's sort of remote or is only listening to process explorer, because the task manager is also clever enough to work out that it's the correct file name.
46:42
So it's using the same APIs. So how about we actually just erase our tracks? Like, can we get rid of the process? I've yet to find a way of getting a process created which actually isn't backed by an executable on disk. I'm sure maybe there's a way, but obviously it's eluded me to the present.
47:00
So you may think, okay, maybe I can just delete the file, or maybe I can just overwrite the file so that you can't see it. Well, if you try and do that with a running process, it doesn't tend to work so well. It complains that demo.exe is open in demo.exe. It's like, thanks, thanks very much. So we can't, in theory, delete or write to an .exe file.
47:24
Oops. But if we go back to how createUserProcess opens files, we'll notice something interesting. When you create a user process, and this is kind of, as I say, because this was the behavior of createProcess originally,
47:40
when it was all done in user mode, it allows you to open a file with additional file access. You can specify, like, I want to open it with these certain access rights, and it's used for createProcess because createProcess wants to be able to read the executable file off disk. So it specifies, say, I want read data permission on this file.
48:02
When createUserProcess returns, it returns a file handle to that, and you can create process internal, can then read it out quite happily. But there's no restriction on what file access we can specify. So what if we specify write access to that? Will we get a writable handle?
48:22
I wouldn't be demoing it, probably otherwise. So, arrays file. So what I'm doing here, I'm going to call createUserProcess. I've specified that I want generic write additional access to the file handle. Now, when it comes back, I can get my file handle,
48:42
and I can just basically slap it with zeros, just get rid of the executable file. And because of the way the image sections work, the image section's loaded into memory, so the process runs, but the file is now zeros and is empty. So, let's see if that works.
49:01
So I run it, we've got woo, hello recon. I just exit that. Interestingly, while you maintain a write access file to that, no one can open that file because of the way the share access works. So I close that down, and then go to our trusty tool, processhacker. And you might go, okay, I want to inspect strings in memory.
49:27
So you go to the memory section. Not the memory section, where is it? Hang on, I think I'm going slightly mad. I'm going to process explorer. So, as you can see, obviously, in the image, there's no strings at all.
49:46
Okay, you may think, big deal. But apparently, in memory, there's no strings either. I think that's because it's reading the P file to work out where the image section data should be, to work out where the strings are. And obviously, there is no P file,
50:01
so it gets completely confused. And if you say, for example, go back to process explorer, it has like an inspect button. It says, huh? Yeah, it doesn't like that too much. And yeah, we've just got an empty file on disk, in theory.
50:28
Sorry. So, completely empty, all zeroed out. Can't do much for that. Obviously, you could DoD secure deleted if you so desired.
50:44
Okay. Wouldn't it be great if you could also delete the file as well? And deleting the file is a bit awkward. Again, it's slightly easier if you use NT create process, but then you've got to do all the horrible stuff
51:01
of actually bootstrapping the entire process. Instead, we want to use create user process. The trouble is, when you create an image section, the operating system locks that file. And effectively, if you then try and issue a delete command to that file, the NTFS driver just returns, sorry, that file is locked.
51:21
You can't actually say you want to delete it. But interestingly, you can specify beforehand you want to delete the file, and the file will only get deleted when the last handle of that file closes. Unfortunately, if you close it while the file is locked, the NTFS driver goes, oh, sorry, that file is locked.
51:41
You still can't delete it. I know you say you can delete it, but you can't delete it. Trust me on that. So we need to somehow make the delete unclosed file close after our process goes away. Because remember, our process, when it closes, when it's terminated, its file handle and its section handle goes away. That then unlocks the file,
52:01
and then we can actually delete it at that point. So I came up with a really like, sort of, yeah, well, this is kind of a self-deletion-ish, self-deletion in inverted commas, really, because you need, obviously, to create the process originally. So the first thing we can do, we can open it for delete access to the original file. And we can do this because, for whatever reason,
52:22
the kernel opens for file share delete, which means that it can share a file handle with a file handle with a delete privilege, a delete permission. We then create our new program.exe process and give it its handle and say, hey, this is the delete unclosed handle for program.exe.
52:41
Do whatever you want with that. Now, in this case, program.exe is a command line application which, in 8 and above, creates the conhost.exe process. And the conhost.exe is what actually displays the console window. And, again, what we do is we pass the handle into conhost.exe.
53:02
But the reason for this is we know conhost.exe will wait for all our processes to go away. And once program.exe closes, conhost.exe will wake up, go, oh, I now need to terminate, I need to close my window, and will then terminate. But at this point, the process handle is gone, or the process is gone,
53:21
and we can actually close our delete unclosed file and it will actually delete it for us. And so, basically, if you kill program.exe, conhost.exe will go away and the file will get deleted and you won't be able to find it anymore. Yeah, if it terminates your file now,
53:42
it gets unlocked and delete succeeds. So, very quick demo. Self-delete. So, in this case, we pre-open the file for delete access. We specify delete unclosed as one of our access requirements
54:00
so that when all the handles close, we'll do it. And then we create the process and it all just, then the magic happens for some definition of magic. So, we can see self-delete.exe is sitting there, waiting to be deleted. We can also see that conhost.exe actually has a file handle to self-delete.exe.
54:24
Okay. So, if we now, oops, I'll just close these down so we can see it both at the same time. And so, if we hit enter, in theory, self-delete.exe should go away.
54:44
Obviously, I can't hit enter. Right. And self-delete.exe goes away and it's gone for good. Okay. Last one. This is just, this was something which Alex mentioned, which I thought I would actually just demonstrate
55:01
because it's kind of like unexpected functionality. And when you actually see it, you go, huh, they've gone to all that effort to block this? Okay. If you try and create an executable using a DLL file, it will fail. And that kind of makes intuitive sense. Why would you try and create a .exe with a .dll?
55:21
Like, a DLL is a dynamic library. It seems to make no sense at all. So, yeah, if you do that, it's obviously going to fail. But it turns out, it doesn't have to be that way. It can be something else entirely. Basically, create process is internal. Consider a special flag in the create info which says,
55:41
if that executable file is a DLL, just don't allow it. This is actually just a standard bit mask. So, for example, if you were feeling, like, a bit desperate for something to do, you can tell it, I want you to create a process from a file which is not actually executable. Probably won't work very well,
56:01
but it does actually work, crazily enough. But, yeah, if you zero this out, you can create processes which are actually backed by DLL files. So, final demo of the day. So, in this case, I'm going to create a process from the DLL,
56:21
and I'm also going to run that DLL in register32. And register32 loads up a DLL file. This will just demonstrate that we can actually load the same thing twice, and it will actually work both ways. So, we hit F5. So, we've got two, obviously, nice windows.
56:40
We've got loads of woos at the back. And, yeah, if we do this, really on an XE is apparently test DLL, according to this. So, it's running as test DLL. But that could just be renamed, it doesn't. XE files don't have to be called .exe files, of course. But, of course, if we look, we can see that,
57:03
trust me, I'm a DLL, is running in register32, and we should have test.dll somewhere. Or apparently not. That was not a very good demonstration, because that demonstrates I might be lying. Oh, no, there it is, right at the top. In complete absence of alphabetic order,
57:24
they stuck T at the top. So, okay. So, you can do that, and people, maybe your incident responder will go, huh, that's kind of odd. Why is it running a DLL? And there we go.
57:41
So, quick wrap-up. So, obviously, the underlying APIs have some unexpected behaviours when it comes to it, but also documentation is a bit lacking when it comes to actually securely creating new processes
58:01
in privileged services especially, and also dealing with things like reference cycles. My initial thought when I found that reference cycle was it's a local DOS. You can basically capture, say, a file handle and never let it up. And the admin can't see the process and can't kill it even if they could see the process, and that actually would help you. But actually, it's a fairly potentially dangerous scenario to be in,
58:25
and it's not even that you need a bug. For example, in a terminal server scenario, if you have two users who cooperate, one user can open one other user's process and use that other user as a mechanism through which to maintain the reference count. And so, potentially, there's some fun to be had on that regard.
58:44
So, thanks for listening to me, and I'm willing to answer any questions, but I think I've basically run out of time. But you can catch me later in the day or tomorrow, and I will be around. So, thanks very much for listening.