Why do you run a desktop environment on your web facing server? Why do you also allow users to login to that server? These are 2 requirements of your server in order to do this exploit. There is a reason it wasn't patched 10 years ago when it was found.
Calm down bro, before you can escalate privileges you need to gain access to the system. If your server has minimal security measurements (no public ssh availability, key authentication), you should‘t be worried about this
Really very nice explaination as always man!! As a software engineer I really learn a lot about security from you and LiveOverflow guy!.. my roomate is also a security engineer, he really enjoys your video too and we both discuss your topic which you cover everytime.
@@raz0229 1. C doesn't have exceptions 2. the value was not null at the time 3. argc must be used to check bounds, and that is the correct solution here
Phenomenal work and explanation. Love it as a programmer. It amazes me how much is really needed to be known about operating systems and their underlying structures in order to find the right "path" to exploitation.
... or sticking to "arbitrary" rules that have been developed over the years... That code should have been fixed, even is there was no exploit. Always assume the attacker is smarter than you; just because *you* can't see an exploit, doesn't mean there isn't one... This is a constant challenge with management types who only react to "big" exploits because they can't "see" the threat...
@@jeschinstad The code violates many rules of defensive programming. The fact that there was a potential out-of-bounds write should have been fixed, regardless of whether it was "exploitable", because you "never know" - as proven by this video.
As an exercise, I looked at the unpatched code, seeing if I could see and fix the flaw in that loop. Man, that code is really hard on the eyes. It was added in 2009 but wouldn't feel out of place in 1990. Ultimately it fell trap to its own complexity (supporting a variable-length argument list with optional parameters, rolling its own parser), together with making a false assumption about the execution environment (that argv[0] always exists).
argv[0] does always exist if argv is defined, but the C language standard has always said that it can be null (when argc is zero), as far as I can tell. So they could have just read the standard document. :)
This is an amazing explaination. It really serves to illustrate how every single package can be a flaw and needs to be maintained, just like when those 11 lines of leftpad were deleted, and it helped me gain root access to my computer, which my parents don't let me use root on. Zero-day exploits are scary, and whenever one is discovered, it helps both the hackers and the defenders...
It's sometimes hard to put into words what you want to see/understand. Your explanation here is exactly what I wanted even if I couldn't quite get it into words. This was perfect ! Thank you
Got here by accident but this is one of the best write-ups I have ever encountered. Clear, concise, good production value -- excellent work. Subbed, belled, this comment, all that algorithm stuff -- thanks for an informative 20 minutes!
@@Dyanosis Thank you, Captain Obvious. "Write Up" == "After Action Report" == "How The FUCK Did He Do THAT?" In future, please leave you petty semantic quibbles by the door. Thank you.
5:15 has some great examples of poor coding practices. L537: g_strdup is called but the next line assumes that it can only be null if the input is null. If libc malloc appears anywhere in that pipeline, then this is a bad assumption, as malloc will return a null pointer if it's unable to fulfill the request. The if statement on L538 assumes that this never happens, which may or may not be the case since we're dealing with g_strdup rather than libc strdup. If I were the original author, I would like to investigate the documentation to make sure those assumptions are true, and if so, document it in a "why" comment. L549: the error enum ENOENT is hardcoded into the error message rather than just letting errno select it. The author assumed that ENOENT is the only possible thing that can go wrong. L552-553: this is a clarity issue. When I first read it, my first thought was that use-after-free undefined behavior was about to be invoked. I quickly realized this wasn't the case when I stepped through the expression in my head and realized that path gets set to s before argv[n] gets set, BUT, reality check: I am a C programmer and I got confused. And If I can be confused, then so can anyone else. It's one more line of code, but path = s; argv[n] = s; is much easier to read and understand. Obvious code > compact code. If you want to min/max on code size, keep it in codegolf challenges, thank you very much You should in general avoid stuffing multiple var declarations and assignments into one line/statement. It may be faster to write, but it's messy and creates more work.
@@anukranan The only thing I can find on that page that remotely pertains to what I said is the passage about the assignment operator yielding an expression, such that a = b = c is equivalent to a = (b = c). I use this for compact conditionals like `while ((ch = getchar()) != EOF)`. That still doesn't make it a good idea to stuff multiple assignment expressions into one line. You're writing code for humans, not for the compiler.
@@anukranan Being able to understand other people's code is an important skill, but it's equally important to advocate for good style and clean code. Sure, I can read a poorly programmed algorithm and figure out "where the variables end up" afterwards. But the difference between clean code and messy code is that I can parse the clean code faster because it's formatted more cleanly and uses less state and side effects. The "git gud" argument only holds up for so long. Eventually, one will come across code written 10 years ago that is thoroughly terrible and full of bugs, and after you finish refactoring it and fixing the bugs, you'll utter to yourself "what idiot wrote this code?"... only to realize that "idiot" was you. There are things that are reasonable to expect programmers to understand, like bitwise operations and idioms like n%2 and *ptr++ = value. And then there's code that tries to be too compact or too clever, and that's where the problems start. Hard to read and hard to understand doesn't mean one is incapable of doing so. It means that it takes longer. And sure, taking a few extra seconds to understand some "clever" code doesn't seem immediately bad, but that time adds up quickly. Having multiple assignments on one line isn't the worst practice, but the reason I consider it bad is because in order to comprehend all of the variables being used in the expression, you have to read it left to right. Since the alternative is doing them one by one on their own lines, left to right is inferior, because it _could_ be written in a way that can be read/scanned much faster. That's my rationale. And you can see it in my code. Every variable used in a function (at function scope) is hoisted to the top and declared separately, and a blank line separates the var declarations from the next "chunk" of code. Sure it results sometimes in a declaration followed by something else followed by that variable being defined proper, but doing it my way results in a clean and rapidly comprehensible manifest of the function's entire state. Also sorry if it takes me a long time to reply. UA-cam doesn't notify me about this thread until someone upvotes it. I got no notification for either of your replies.
L537: g_strdup calls g_new which calls g_malloc which calls malloc. I'm not even making that clusterf*k up, so yeah... it returns a null if malloc does. Did I mention all this chain of calls really does is call malloc and strcpy from the C library? GLib belongs in the trashcan. The library is basically C with G_ brand stuck in front of it.
The critical missing piece of information for people like me is that there's a permission bit on the pkexec file itself that says "when joe schmo runs this program, run the program as if it was actually run by the owner of the program" (that owner being root, in this case). I was coming into this thinking that it was going to call some operating system function or something and didn't realize that the pkexec code itself is priviledged just because of the bits in its inode.
Thanks, I was also confused by this! The video was just describing a lot of steps to make that program do something ... that you could just do in your own program that would be trivial to write. The fact that program runs in a privileged context is a critical prerequisite of the exploit that I'm surprised the video didn't mention.
@@0raj0 Well it took me a good few seconds of confused thinking to connect the dots, i vaguely knew but it still took me a bit. For sure it would have been better had he mentioned it somewhere, like half a sentence.
Tbh I originally thought it was a privileged system service situation and was thinking "ok so I can start this program under my permissions, but *how do I get it to be involved by the system*" but this clarifies that. Thanks!
I think you're the only developer in yt with great UI and nice thumbnail and very understandable explanation, your only weak point is that you upload videos so lately, but whatever It was Great! :)))
Perfect explanation. Basically it shows why we have guide lines and best practices in coding. A simple Lint or MISRA analysis would have caught this before release.
Very interesting topic. I had no idea that the BRUH charset exploit could cause this much harm to a computer system, I really have to double check that my calculator cannot be abused in this way.
This is so simplistically brilliant. I love to think that this person was thinking "I wonder if this would work" and it did. I love having the same thoughts coding something, and when it works "Hell ya" In this case, it's a major exploit but, same thing lol Great video. I subbed.
this was such an interesting accidental exploit. i imagine being able to read a variable as an argument has quite a few uses in a system, not necessarily just malicious ones either.
@@xakthos no way its an accident. govt bribes and threatens companies and people to install backdoors under threat of vanishing. putting something like that in a program is easily within their bag of tricks. you just wont find anything about it via google. its a search engine and they can omit results. govt just needs to threaten google to omit results, and companies like money and being in business, easy choice for them.
Your speaking is very clear! I'm not a native English speaker and I can't understand very well other people, but you I can. Thank you for the video, +1 subscriber!
This world is rapidly passing away and I hope that you repent and take time to change before all out disaster occurs! Belief in messiah alone is not enough to grant you salvation - Matthew 7:21-23, John 3:3, John 3:36 (ESV is the best translation for John 3:36) if you believed in Messiah you would be following His commands as best as you could. If you are not a follower of Messiah I would highly recommend becoming one. Call on the name of Jesus and pray for Him to intervene in your life - Revelation 3:20. Contemplate how the Roman Empire fulfilled the role of the beast from the sea in Revelation 13. Revelation 17 confirms that it is in fact Rome. From this we can conclude that A) Jesus is the Son of God and can predict the future or make it happen, B) The world leaders/nations/governments etc have been conspiring together for the last 3000+ years going back to Babylon and before, C) History as we know it is fake. You don't really need to speculate once you start a relationship with God. Can't get a response from God? Fasting can help increase your perception and prayer can help initiate events. God will ignore you if your prayer does not align with His purpose (James 4:3) or if you are approaching Him when "unclean" (Isaiah 1:15, Isaiah 59:2, Micah 3:4). Stop eating food sacrificed to idols (McDonald's, Wendy's etc) stop glorifying yourself on social media or making other images of yourself (Second Commandment), stop gossiping about other people, stop watching obscene content etc. Have a blessed day!
pkexec is the GUI password prompt that pops up on most Linux distros to run GUI apps as root.. some distros disguise the program as gtksu or kdesu but nowdays even if the window says its gtksu or kdesu its actually pkexec
I have no prior knowledge in anything related to computers besides high school B.S. classes and trying to understand this feels like taking 12 hits of acid and trying to befriend a octopus… and man I’m loving it. Frankly I don’t even know what Lenix is but your penguin avatar and the sporadic nature of the code has my brain in “I need more information” mode so I figure I’m going to be here more often from now on
Linux is another operating system--an open-source equivalent of UNIX. UNIX is what Mac OS X is based on, but UNIX itself is much lower-down and barebones than OS X, for OS X, Apple just licensed UNIX and built a pretty window manager on top of it. Anyway Linux is similarly low-down and barebones--you can install pretty window managers on top of it (Android is built on top of Linux) but you don't need to, and for this reason and for its general stability it's very popular for web servers and systems which need to be on for a long time.
@@User2o2 It's not by a different company, it was made and is managed by the open source community. Aka, it's owned by everyone. People on the internet out of the kindness of their hearts maintain it, and so many companies use it they pay to people to maintain it.
When you first showed the start of pkexec it directly looked fishy. Writing back to argv is a big no no. The few bytes saved in allocation are not worth it. On top of that not reading from argv without checking against argc is also something you learn as a beginner of c programming. These entire first couple lines of the main are totally bunkers.
@@buzifalus honestly thats exactly my thought. US govt had a backdoor of sorts into pretty much every system running RSA encryption years ago. pretty much the entire world was vulnerable to it except the CIA and a few tech collages, both of which had their own seeds rather then trusting the default. To be fair, virtually nobody understood the security well enough to feel safe making their own or trusting someone to do it. It just so happened that the US govt had the seed though so cracking anything using RSA encryption was trivial. They only got caught when they had RSA put out a "security improvement" which when the security community tested, compared to previous versions, you could crack passwords even faster. They called out RSA since this was impossible to miss and the president of RSA outed that govt had forced him and his company to share the seed as well as implement this 'improvement', they were also paid for it. After the govt lost that they began work on PRISM, that spy system the US govt was using that edward snowden outed. they were pushing it into more and more companies and had claims it was in a few major ones, those companies deny it, but what else can they do say 'yeah the govt forced us to put in a backdoor for them to access your data and we didnt tell you or fight it in court' they would lose customers instantly. So the idea that this could have been put in place on purpose is 100% possible and definitely something the govt would do. too many bad practices that all line up to allow a massive exploit. We can look forward to the new windows exploit. windows 11 with a 'security' chip on the motherboard, that windows 11 wont work without, and that whole 'windows 10 will be our last version ever, we will keep updating it' suddenly it looks like the govt stepped in and said 'we want everyone on our new backdoor version'.
@@jessiejanson1528 A lot of information about this has been scrubbed from the internet as well, including entire Wikipedia pages which had legitimate sources.
@@jessiejanson1528 This is a beautiful reason why buzzwords like e2e are misdirections. If you are communicating really really really sensitive information, Big Brother may still be able to watch them be it in whatsapp or opensignal. If youre a commoner like me then don't bother beyond basic encryption, as whatsapp frontend can scrape the data once it decrypts it anyways. You only need avoid random scammer-hackers from knowing about you.
Classic "clever code syndrome" where the programmer tries to do something clever, misses some edge case, makes the code a nightmare to maintain and introduces bugs to the system all in the name of saving insignificant amounts of runtime and memory... really makes you wonder how a package like that got shipped with major linux distros
The Hated One showed your channel temporarily in his latest video about youtube blacklisting him :P I was like; "Omg, that's one of my favourite channel!!!"
now ive only been studying computer science/coding for a few months now and i am not very knowledgeable in this kinda stuff but your explanation actually made it fairly clear to someone with little coding experience.
3:46 I think, in the application the thing that separates the arguments from the environment variables is nothing. If you read after argc, you are in the environment variables space. I think NULL is only used by execve to determine the number of arguments passed
There is no boundary in the memory where the actual strings are stored, but the argv array of pointers into that memory is terminated with a null pointer.
For me, the weirdest parts in here are: 1. Writing back to argv. That is usually a red alert. 2. Having a conversion executable with setuid bit set or capable of running as root. I don't know about other exploits but this specific one wouldn't be one I'd ever end up doing.
@@PwnFunction yes I then realized we were talking about execve and not running the program "normally" I got confused because by talking about having NULL in argv[0] I was hearing that as setting the first argument to NULL, while we are not actually setting any argument at all
I clicked this cause the title was interesting, but almost immediately clicked off of it thinking it would be over my head as someone with only novice level experience with any programming (VB in excel) or Linux. But this was actually well presented without overly dumbing it down to the point of making it boring. It’s still a little bit over my head, but I got the gist of it.
first time watching ur videos and i already love it man, ur voice is calming and u explain coding stuff why better than my own teacher and if u were my teacher I would love to listen to u explain coding all day. keep up the amazing work man.
as soon as I saw "argv[n] = path = s;" I had to wonder why on earth anybody would write to the arguments. As far as I'm aware, that's something nobody is supposed to do.
@@gabrielpar3519 Goto bashing is so 1980! ;) Seriously - once compiled, there are gotos everywhere (JMP, JAL, JZ, JNZ,...). If used in the right scenario it can lead to more expressive code than avoiding it at any cost ever could.
Man, I need to get back into this. Did a stint with gov't contractor for an internship, we focused on a lot of this stuff. The biggest vulnerabilities we took advantage of in Linux is a general trust in modules, we could gain a lot of control of a system that way, just like with that control-mod you had.
True, though Linux basically hand over more tools for you to secure your machine against exploits like this such as AppArmor/SELinux which can restrict programs what they can do with root privilege. Windows equivalence is Mandatory Integrity Control which is pretty crap in comparison especially on Windows 11 which breaks everything.
@Synth Depends on how you define a good language. People say JavaScript isn't a good language because it allows you to shoot yourself in the foot, well C allows you to freakin nuke your hometown. With great power comes great risks. Other languages will just give an API to access args and another for envs.
@Synth what about rust lol? Well that's a point not using such low level languages and rely to virtual machines. C doesn't even has smart pointers, absolute trash
Cool explanation. I used the berdav's exploit for this in a CTF about a month ago, worked like a charm. _(I'd also recommend you include the CVE number in your title, it's sure to drive traffic/views.)_
I think this becomes clear when he shows the code of the exploit at 12:00. It's a bit surprising that execve allows argv[0] == null to be passed to the child process.
Nice video, I thoroughly enjoyed it. One thing that was bothering me though: Why can't you just LD_PRELOAD over g_printerr and save yourself this GCONV business? When you talk about using LD_PRELOAD, and then saying there's a problem because clearenv() is called, I think you're actually missing the fundamental reason why LD_PRELOAD won't work here. LD_PRELOAD is processed before main() is executed (i.e., preloaded). This means we can't actually overwrite any functions because the env var doesn't exist at load, we only get to add env vars after loading. That's why GCONV is necessary here, because it gets processed during execution instead of only at load time.
This world is rapidly passing away and I hope that you repent and take time to change before all out disaster occurs! Belief in messiah alone is not enough to grant you salvation - Matthew 7:21-23, John 3:3, John 3:36 (ESV is the best translation for John 3:36) if you believed in Messiah you would be following His commands as best as you could. If you are not a follower of Messiah I would highly recommend becoming one. Call on the name of Jesus and pray for Him to intervene in your life - Revelation 3:20. Contemplate how the Roman Empire fulfilled the role of the beast from the sea in Revelation 13. Revelation 17 confirms that it is in fact Rome. From this we can conclude that A) Jesus is the Son of God and can predict the future or make it happen, B) The world leaders/nations/governments etc have been conspiring together for the last 3000+ years going back to Babylon and before, C) History as we know it is fake. You don't really need to speculate once you start a relationship with God. Can't get a response from God? Fasting can help increase your perception and prayer can help initiate events. God will ignore you if your prayer does not align with His purpose (James 4:3) or if you are approaching Him when "unclean" (Isaiah 1:15, Isaiah 59:2, Micah 3:4). Stop eating food sacrificed to idols (McDonald's, Wendy's etc) stop glorifying yourself on social media or making other images of yourself (Second Commandment), stop gossiping about other people, stop watching obscene content etc. Have a blessed day!
One thing I don't understand is why the for loop is entered at all. If the first element of argv is NULL, then argc should be equal to 0, right? **Edit:** nvm, the loop doesn't have to be entered at all for this to work.
Right. It has to create n and initialize it to 1 before it can compare it to anything. The comparison returns false so the body of the loop is not entered but n is still 1
Think I understood like 20% of this video... at best. But it was somehow still interesting enough to keep me till the end :D So that must be a good sign for you, Sir.
I know that we're technically allowed to modify the arguments in this way, and merely changing what argv points to isn't precisely wrong, but this is definitely some bad juju. While it would be less efficient, in this case I think safety should trump efficiency and it'd be better to just copy argv and modify your own copy.
@@szr8 It doesn't modify what shows up in 'ps', just what argv[0] points to. Remember, the array that is argv is on the stack. So everything it points to is considered read-only, but the pointers on the stack are not. You can't change argv[0][0], but you can change argv[0];
@@anon_y_mousse Afaics, the code here didn't change argv[1][0], just argv[1]. Same thing. The problem is just that argv[1] is an alias for env[0] in this setup.
@@ccreutzig Actually, I just had a look at the code in question. Turns out it doesn't modify argv at all. I guess I should pay attention better. Apparently, the whole bug is in calling it with an empty argv, because it skips past argv[0] which when using exec*() like this can be empty. Moral of the story with this code, is don't expect that you're being called with your program name as argv[0]. Though, I stand by my statement that you should never modify argc and argv regardless of what you're doing.
@@ccreutzig Actually, disregard most of the previous comment too, I was looking at the updated code by mistake, and it does alter argv. However, the problem is that they expected argv[0] to point somewhere that it doesn't, and they didn't properly account for a 0 length argv.
After watching the video, i wondered why this is even possible in the first place, as the system calls setuid() and setgid() that you mentioned at 14:38 should already fail with "Permission denied". After looking around for a bit, I noticed the special user file permission "rws" instead of "rwx" for the program pkexec. Only because of the "s" flag pkexec is even allowed to call setuid() and setgid(), so any other preinstalled program with special file permissions will have the same vulnerability if not adressed in the code properly.
Just when you think your password was great you come in to find a user logged in without requiring a password and you are like.... how did you do that?
Hey, quick question, if the first argument in argv is set to null, what is the value of argc? I would assume that it would be 0 or 1, but that's clearly not true Edit to say that I messed around with this actual code some, and this does not run within the for loop, and that n is a global variable, so it doesn't exit scope before the invalid write is executed.
Yer, it's the usual problem of allowing a variable (n) to exist beyond the scope that it's needed for. If you really have to use globals, you need to do some sanity checking before you use them.
@@HenryLoenwind Indeed. I consider myself as an experienced C programmer and I was shocked to discover that argc can be 0. Using a 'for' or 'while' loop starting at index 1 is a pretty standard way to process arguments in C/C++. Pretty much any tutorial about argument processing in C is using such a loop. There are probably thousands of applications that could be abused in a similar way. Of course, most of them do not run setuid so that should not matter much (there are far easier ways to 'hack' a non-setuid program).
I have an improvement suggestion: Please use dark mode in your code editor. It is very stressful for the eyes if the video switches between light and dark mode. Thank you 🙂
This is a great video. I'd appreciate a full diagram of the layout of argc and argv with pointers as well -- even if you don't wanna fully explain c string layout, just having a picture can be helpful. Like, have little squares showing character boundaries or something
Well said! Having to deal with too low-level implementation details together with the business logic makes us defocused and it's too easy to make mistakes.
Question: Did some one run a malicious app on a system to figure this out? From the explanation you gave, one would need to be at the given terminal for this exploit to work. But it was my understanding this was being triggered remotely. Did I miss something?
It's a privilage ESCALATION attack, meaning the system has already been breached or you have access already but as a low permision user and you are giving yourself better perms in order to do more detrimental things (like edit something you arent supposed to or view confidential information). A good example might be that you have remoted into a file sharing server and then as a guest on the server you run the code, get root, then add a new user to access everything with or maybe open a new reverse shell or smthn
the exploit has to be executed by the 'local' machine. That can be triggered remotely through ssh, since polkit is an exec you can reach without sudo. Not necessarily like you open an email and suddenly your system deletes itself. You gotta have a keyboard connection (like ssh) to execute this, or the user has to be tricked into executing it by hiding it in something like an app install executable. as far as how did someone find out? It was found by some nerds at a security company, so more than likely they spent a week looking through polkit's source out of curiousity and found this. Coordinated media release on jan 25th in order to give RedHat a 2 month warning
@@teal8365 Well it doesn't only have to be ssh or user error. You can also get a shell/terminal by using an attack what's known as a "reverse shell". Many languages include some way of opening up a child process or making an http request, which is vulnerable to exploitation
Not only terminal access, but the machine needs a desktop environment installed as well, because these packages don't install otherwise.. they are for popup password prompts, which are only on DEs. I manage many servers with many different distros and none of them have pkexec on them because they're all headless. If your users don't have access to those prompts (which is pretty standard) you're already blocking access to this executable as well, so they couldn't even execute it.. so really right place right time type of exploit. There are many escalation attacks when you have this type of physical access.
First video of yours I've seen, but loved it. Knew about the exploit (and of course updated my servers) but never really understood it under the hood. Crazy what we programmers can do when we don't know what we're doing! 🤪
This is why we really can't trust the 'many eyes' security philosophy of open source. Really nasty bugs like this are uncovered all the time even in Linux code, yet there are supposedly large numbers of programmers going through this stuff with a fine-toothed comb. Problem is there just aren't nearly enough programmers, particularly in packages maintained by just one or two people in practice. Even Linted code with lots of warnings makes it through quality control because people just aren't paid enough to care.
That's assuming this bug was not intentional on somebody's part. Who knows what inducements and/or persuasion is applied to those few who are meant to "insect" code for bugs?
@@YodaWhat Very good point, too. And when we look at the numbers of discovered, exploitable bugs like this, we find that they're not much different to closed source software, and are sometimes worse, with worse effect because so many people use OSS.
Windows users when there’s a security flaw: “THE END OF THE WORLD IS INEVITABLE WERE ALL GONNA DIE” Linux users when there’s a security flaw: “pretty cool right?”
5:20 The first one which jumped to my mind was, that the argument array is implicitly constant (yes, even if you don't state it), at least according to the language standard.
I'm confused by one thing. Consider the expected case where argc > 0. The for loop goes for (n = 1; n < (guint) argc; n++) So at the end of this loop, we should have n == argc. Since nothing happens to n between here and this section g_assert (argv[argc] == NULL); path = g_strdup (argv[n]); if (path == NULL) It should be the case (especially with that assert) that argv[n] == NULL. So the next two lines just set path to NULL then check if it is, which doesn't make much sense to do. Am I missing something?
Presumable there's a "break" inside the loop, something like "if argv[n] == "--" /* end of parameter list marker */ break;" Um, on second thought...: "if (argv[n] is not a flag) break;" is more likely.
Great explanation! Such a dangerous vulnerability hidden for all these years... Man, I wonder if someone had already exploited this in a regular way without disclosing it. Probably agencies LOL
thats basically a c vulnerability. Thankfully the linux ecosystem is moving to rust, where this wouldnt be possible. (In rust, if you request an element of an list that doesnt exist, the program crashes with an error message. )
@@askeladden450 Really depends on the exact code. Most likely, if you tried to write something very similar, you'd get a panic on the attempted out of bounds access. Though this is really not how you'd write this in Rust. 99.9% of the time you'd just use clap (or maybe some other proper arg parsing lib) or at the very least you wouldn't determine the length of the arguments by checking for a null pointer and similar weird stuff. Realistically, this is something that pretty much every slightly higher level language would prevent. But Rust is one of the few languages that have low-level speed and access with the safety of a high-level language.
High level languages are great, but one sacrifices performance and excellent quality low level code by using them. You can't have your cake and eat it too. Saying just use this is or that high language doesn't solve this general problem. There is no substitute for putting in the labor for well designed, cross analyzed for weakness, and heavily tested code.
damn, those c programmers really didn't care about stuff. Even my amateur code looks way more structured. And this is sudo-like software, sure THEY must've known a thing or two about privilege-escalation aren't they
I mentioned Lennox ONCE, next day BAM this gets suggested to me by UA-cam. I know nothing of Lennox. I have never looked up anything like this. WoOoOOOOoO spoopyyy
BRUH
BRUH
stole my first comment lmao
Yes
ok
sussy very sussy indeed bruh (y)
0:13
"Pretty cool, right?" As a person who operates a web-facing server, this is terrifying. No coolness. Just pure terror.
Why do you run a desktop environment on your web facing server? Why do you also allow users to login to that server? These are 2 requirements of your server in order to do this exploit. There is a reason it wasn't patched 10 years ago when it was found.
@@gg-gn3re They're just reacting to the first bit, not the whole video.
@@gg-gn3re It's not that. It's the mentality you gain from it.
Calm down bro, before you can escalate privileges you need to gain access to the system. If your server has minimal security measurements (no public ssh availability, key authentication), you should‘t be worried about this
@@leroyjenkins1911 if you're saying this i suspect you didn't quite see log4j "recent" exploit right? i'll just imagine that you didn't.
Really very nice explaination as always man!! As a software engineer I really learn a lot about security from you and LiveOverflow guy!.. my roomate is also a security engineer, he really enjoys your video too and we both discuss your topic which you cover everytime.
your lucky to have a roommate to discuss that stuff with lol. My friends rudely cut me off
@@kevinalexander4959 i dont think those are friends bro
FYI, we were roomates in college and we are working in the same city so we live together as roomates again. We are from Bangalore - India.
@@aditya.ishan27 so you're both black, you have nothing to be ashamed of
@@Angel-Pizzaeater Really? You just HAD to bring RACE into a positive comment...
I have a fix for this: simply block any access to folders/files containing "pwn" in their names. I'll collect my Turing award now thank you very much
Simplest things would be to give all users root-access, then they would not try todo this. I will wait for my Nobel Prize.
Wouldn't it be easier to just throw an OutOfBounds exception if encountered 'null' while reassigning path in pkexec.c
@@AndrewTSq If everyone is a root user, then no one is a root user. Simple!
@@raz0229
1. C doesn't have exceptions
2. the value was not null at the time
3. argc must be used to check bounds, and that is the correct solution here
i have a simpler fix: just destroy your pc and boom they cant hack it anymore
Phenomenal work and explanation. Love it as a programmer. It amazes me how much is really needed to be known about operating systems and their underlying structures in order to find the right "path" to exploitation.
Yeah, it's not exactly like Hollywood :)
... or sticking to "arbitrary" rules that have been developed over the years... That code should have been fixed, even is there was no exploit.
Always assume the attacker is smarter than you; just because *you* can't see an exploit, doesn't mean there isn't one...
This is a constant challenge with management types who only react to "big" exploits because they can't "see" the threat...
Eh not really,
@@edwardcullen1739: What are you referring to?
@@jeschinstad The code violates many rules of defensive programming. The fact that there was a potential out-of-bounds write should have been fixed, regardless of whether it was "exploitable", because you "never know" - as proven by this video.
As an exercise, I looked at the unpatched code, seeing if I could see and fix the flaw in that loop. Man, that code is really hard on the eyes. It was added in 2009 but wouldn't feel out of place in 1990. Ultimately it fell trap to its own complexity (supporting a variable-length argument list with optional parameters, rolling its own parser), together with making a false assumption about the execution environment (that argv[0] always exists).
argv[0] does always exist if argv is defined, but the C language standard has always said that it can be null (when argc is zero), as far as I can tell. So they could have just read the standard document. :)
This seems like the type of thing though that the exploit was known for a while but only got executed years later
@@X_Baron do you think Red Hat (creator of this crap along other amazing turds like systemd) care about standards lol
is it even normal practice? how common is writing your own cli parser? I imagine there has to be some standard and safe way or a lib to do it
As far as I can understand, the false assumption is that argv[1] exists.
This is an amazing explaination. It really serves to illustrate how every single package can be a flaw and needs to be maintained, just like when those 11 lines of leftpad were deleted, and it helped me gain root access to my computer, which my parents don't let me use root on. Zero-day exploits are scary, and whenever one is discovered, it helps both the hackers and the defenders...
your parents?🤣
@@clivejameston7557 yeah? why is that funny to you, it just means there is parental controls.
is your father linus torvalds? heh
@@clivejameston7557 I don't get the joke
how did the deletion of leftpad help you gain root access?
It blows my mind how I've been coding for years now and stuff like this still feels like complete gibberish lol. Amazing explanation.
I understand pointers, but I have no idea how C pointers work LMAO, the pointer star notation is still kinda confusing
@@Rudxain OS level coding is a completely different ball game lmao
@@Rudxain
y = 0;
int* x;
@@Rudxain int* x declares pointer variable x. The variable x now stores an adress. *x will get the value stored at the address in the variable x
@@drakey6617 Thank you for clearing my confusion, it seems more simple now
It's sometimes hard to put into words what you want to see/understand. Your explanation here is exactly what I wanted even if I couldn't quite get it into words.
This was perfect ! Thank you
Got here by accident but this is one of the best write-ups I have ever encountered. Clear, concise, good production value -- excellent work. Subbed, belled, this comment, all that algorithm stuff -- thanks for an informative 20 minutes!
Write up? You mean video? This is hardly in written form.
@@Dyanosis Thank you, Captain Obvious. "Write Up" == "After Action Report" == "How The FUCK Did He Do THAT?"
In future, please leave you petty semantic quibbles by the door. Thank you.
5:15 has some great examples of poor coding practices.
L537: g_strdup is called but the next line assumes that it can only be null if the input is null. If libc malloc appears anywhere in that pipeline, then this is a bad assumption, as malloc will return a null pointer if it's unable to fulfill the request. The if statement on L538 assumes that this never happens, which may or may not be the case since we're dealing with g_strdup rather than libc strdup. If I were the original author, I would like to investigate the documentation to make sure those assumptions are true, and if so, document it in a "why" comment.
L549: the error enum ENOENT is hardcoded into the error message rather than just letting errno select it. The author assumed that ENOENT is the only possible thing that can go wrong.
L552-553: this is a clarity issue. When I first read it, my first thought was that use-after-free undefined behavior was about to be invoked. I quickly realized this wasn't the case when I stepped through the expression in my head and realized that path gets set to s before argv[n] gets set, BUT, reality check: I am a C programmer and I got confused. And If I can be confused, then so can anyone else. It's one more line of code, but path = s; argv[n] = s; is much easier to read and understand. Obvious code > compact code. If you want to min/max on code size, keep it in codegolf challenges, thank you very much
You should in general avoid stuffing multiple var declarations and assignments into one line/statement. It may be faster to write, but it's messy and creates more work.
@@anukranan The only thing I can find on that page that remotely pertains to what I said is the passage about the assignment operator yielding an expression, such that a = b = c is equivalent to a = (b = c). I use this for compact conditionals like `while ((ch = getchar()) != EOF)`.
That still doesn't make it a good idea to stuff multiple assignment expressions into one line. You're writing code for humans, not for the compiler.
@@anukranan Being able to understand other people's code is an important skill, but it's equally important to advocate for good style and clean code. Sure, I can read a poorly programmed algorithm and figure out "where the variables end up" afterwards. But the difference between clean code and messy code is that I can parse the clean code faster because it's formatted more cleanly and uses less state and side effects.
The "git gud" argument only holds up for so long. Eventually, one will come across code written 10 years ago that is thoroughly terrible and full of bugs, and after you finish refactoring it and fixing the bugs, you'll utter to yourself "what idiot wrote this code?"... only to realize that "idiot" was you.
There are things that are reasonable to expect programmers to understand, like bitwise operations and idioms like n%2 and *ptr++ = value. And then there's code that tries to be too compact or too clever, and that's where the problems start. Hard to read and hard to understand doesn't mean one is incapable of doing so. It means that it takes longer. And sure, taking a few extra seconds to understand some "clever" code doesn't seem immediately bad, but that time adds up quickly. Having multiple assignments on one line isn't the worst practice, but the reason I consider it bad is because in order to comprehend all of the variables being used in the expression, you have to read it left to right. Since the alternative is doing them one by one on their own lines, left to right is inferior, because it _could_ be written in a way that can be read/scanned much faster.
That's my rationale. And you can see it in my code. Every variable used in a function (at function scope) is hoisted to the top and declared separately, and a blank line separates the var declarations from the next "chunk" of code. Sure it results sometimes in a declaration followed by something else followed by that variable being defined proper, but doing it my way results in a clean and rapidly comprehensible manifest of the function's entire state.
Also sorry if it takes me a long time to reply. UA-cam doesn't notify me about this thread until someone upvotes it. I got no notification for either of your replies.
L537: g_strdup calls g_new which calls g_malloc which calls malloc. I'm not even making that clusterf*k up, so yeah... it returns a null if malloc does. Did I mention all this chain of calls really does is call malloc and strcpy from the C library? GLib belongs in the trashcan. The library is basically C with G_ brand stuck in front of it.
I'm a noob when it comes to this level of OS programming stuff, but I really like the way you explain it.
The critical missing piece of information for people like me is that there's a permission bit on the pkexec file itself that says "when joe schmo runs this program, run the program as if it was actually run by the owner of the program" (that owner being root, in this case).
I was coming into this thinking that it was going to call some operating system function or something and didn't realize that the pkexec code itself is priviledged just because of the bits in its inode.
Thanks, I was also confused by this! The video was just describing a lot of steps to make that program do something ... that you could just do in your own program that would be trivial to write.
The fact that program runs in a privileged context is a critical prerequisite of the exploit that I'm surprised the video didn't mention.
If you know what pkexec command is used for (it's basically a graphical equivalent of sudo), then this is pretty obvious.
@@0raj0 Well it took me a good few seconds of confused thinking to connect the dots, i vaguely knew but it still took me a bit. For sure it would have been better had he mentioned it somewhere, like half a sentence.
@@SianaGearz he did, at some point near the beginning of the video, he describes what pkexec does.
Tbh I originally thought it was a privileged system service situation and was thinking "ok so I can start this program under my permissions, but *how do I get it to be involved by the system*" but this clarifies that. Thanks!
I think you're the only developer in yt with great UI and nice thumbnail and very understandable explanation, your only weak point is that you upload videos so lately, but whatever It was Great! :)))
I think it's good that he uploads lately. Quality over Quantity: If he would upload faster, the other aspects would suffer(thumbnail, UI, etc.)
LiveOverflow is also pretty great.
@@danielalorbi thanks, a minecraft developer :))
Btw HorseNuggets is minecraft developer too
0:09 Well that escalated quickly
Perfect explanation. Basically it shows why we have guide lines and best practices in coding.
A simple Lint or MISRA analysis would have caught this before release.
Very interesting topic. I had no idea that the BRUH charset exploit could cause this much harm to a computer system, I really have to double check that my calculator cannot be abused in this way.
I have 0 experience with coding in my life, but you explained it so clearly even I understood it.
This is so simplistically brilliant.
I love to think that this person was thinking "I wonder if this would work" and it did.
I love having the same thoughts coding something, and when it works "Hell ya"
In this case, it's a major exploit but, same thing lol
Great video. I subbed.
Yep. I love that feeling when you wonder if something will work and it does. I'm not a very good programmer so when ideas work, i am ecstatic.
this was such an interesting accidental exploit. i imagine being able to read a variable as an argument has quite a few uses in a system, not necessarily just malicious ones either.
True
Was it accidental, really? A good coder can make a minor 'mistake' and leave a huge whole. Some aren't accidents.
@@xakthos no way its an accident. govt bribes and threatens companies and people to install backdoors under threat of vanishing. putting something like that in a program is easily within their bag of tricks. you just wont find anything about it via google. its a search engine and they can omit results. govt just needs to threaten google to omit results, and companies like money and being in business, easy choice for them.
@@xakthos hole*
Imagine dynamically linking security critical software.
LOOOOOOL
Windows moment
Finally a new video, love your content Ty
Your speaking is very clear! I'm not a native English speaker and I can't understand very well other people, but you I can. Thank you for the video, +1 subscriber!
I have barebones programming knowledge. And your explanation still made complete sense to me. You sir have a gift! Cheers!
Same I understand the basics and I could tell how everything is supposed to play but don't understand the functions of them 😅
This world is rapidly passing away and I hope that you repent and take time to change before all out disaster occurs! Belief in messiah alone is not enough to grant you salvation - Matthew 7:21-23, John 3:3, John 3:36 (ESV is the best translation for John 3:36) if you believed in Messiah you would be following His commands as best as you could. If you are not a follower of Messiah I would highly recommend becoming one. Call on the name of Jesus and pray for Him to intervene in your life - Revelation 3:20.
Contemplate how the Roman Empire fulfilled the role of the beast from the sea in Revelation 13. Revelation 17 confirms that it is in fact Rome. From this we can conclude that A) Jesus is the Son of God and can predict the future or make it happen, B) The world leaders/nations/governments etc have been conspiring together for the last 3000+ years going back to Babylon and before, C) History as we know it is fake. You don't really need to speculate once you start a relationship with God.
Can't get a response from God? Fasting can help increase your perception and prayer can help initiate events. God will ignore you if your prayer does not align with His purpose (James 4:3) or if you are approaching Him when "unclean" (Isaiah 1:15, Isaiah 59:2, Micah 3:4). Stop eating food sacrificed to idols (McDonald's, Wendy's etc) stop glorifying yourself on social media or making other images of yourself (Second Commandment), stop gossiping about other people, stop watching obscene content etc. Have a blessed day!
Next level of Genius, man! I'm a C++ Dev, and it's Mind-blowing to me!
This sounds a lot like a DLL side-loading attack in Windows, where a legitimate program loads a malicious dependency
pkexec is the GUI password prompt that pops up on most Linux distros to run GUI apps as root.. some distros disguise the program as gtksu or kdesu but nowdays even if the window says its gtksu or kdesu its actually pkexec
I most likely haven't subscribed to anyone in like 7 years, good job, well subbed :) .
I have no prior knowledge in anything related to computers besides high school B.S. classes and trying to understand this feels like taking 12 hits of acid and trying to befriend a octopus… and man I’m loving it. Frankly I don’t even know what Lenix is but your penguin avatar and the sporadic nature of the code has my brain in “I need more information” mode so I figure I’m going to be here more often from now on
Linux is another operating system--an open-source equivalent of UNIX.
UNIX is what Mac OS X is based on, but UNIX itself is much lower-down and barebones than OS X, for OS X, Apple just licensed UNIX and built a pretty window manager on top of it.
Anyway Linux is similarly low-down and barebones--you can install pretty window managers on top of it (Android is built on top of Linux) but you don't need to, and for this reason and for its general stability it's very popular for web servers and systems which need to be on for a long time.
In English, he means it’s like Windows but made by a community of people and it has more options
@@User2o2 It's not by a different company, it was made and is managed by the open source community. Aka, it's owned by everyone. People on the internet out of the kindness of their hearts maintain it, and so many companies use it they pay to people to maintain it.
I love this comment
@@User2o2 i figured the guy was in high school, he should at least be able to understand 3/4 of what i was saying and he could google the rest.
When you first showed the start of pkexec it directly looked fishy. Writing back to argv is a big no no. The few bytes saved in allocation are not worth it. On top of that not reading from argv without checking against argc is also something you learn as a beginner of c programming. These entire first couple lines of the main are totally bunkers.
Polkit is also a fishy name ending up as a rootkit instead. Gotta wonder which agency needed that hole
@@buzifalus honestly thats exactly my thought. US govt had a backdoor of sorts into pretty much every system running RSA encryption years ago. pretty much the entire world was vulnerable to it except the CIA and a few tech collages, both of which had their own seeds rather then trusting the default. To be fair, virtually nobody understood the security well enough to feel safe making their own or trusting someone to do it. It just so happened that the US govt had the seed though so cracking anything using RSA encryption was trivial. They only got caught when they had RSA put out a "security improvement" which when the security community tested, compared to previous versions, you could crack passwords even faster. They called out RSA since this was impossible to miss and the president of RSA outed that govt had forced him and his company to share the seed as well as implement this 'improvement', they were also paid for it. After the govt lost that they began work on PRISM, that spy system the US govt was using that edward snowden outed. they were pushing it into more and more companies and had claims it was in a few major ones, those companies deny it, but what else can they do say 'yeah the govt forced us to put in a backdoor for them to access your data and we didnt tell you or fight it in court' they would lose customers instantly.
So the idea that this could have been put in place on purpose is 100% possible and definitely something the govt would do. too many bad practices that all line up to allow a massive exploit.
We can look forward to the new windows exploit. windows 11 with a 'security' chip on the motherboard, that windows 11 wont work without, and that whole 'windows 10 will be our last version ever, we will keep updating it' suddenly it looks like the govt stepped in and said 'we want everyone on our new backdoor version'.
@@jessiejanson1528 A lot of information about this has been scrubbed from the internet as well, including entire Wikipedia pages which had legitimate sources.
@@jessiejanson1528 This is a beautiful reason why buzzwords like e2e are misdirections. If you are communicating really really really sensitive information, Big Brother may still be able to watch them be it in whatsapp or opensignal. If youre a commoner like me then don't bother beyond basic encryption, as whatsapp frontend can scrape the data once it decrypts it anyways. You only need avoid random scammer-hackers from knowing about you.
Classic "clever code syndrome" where the programmer tries to do something clever, misses some edge case, makes the code a nightmare to maintain and introduces bugs to the system all in the name of saving insignificant amounts of runtime and memory... really makes you wonder how a package like that got shipped with major linux distros
The Hated One showed your channel temporarily in his latest video about youtube blacklisting him :P
I was like; "Omg, that's one of my favourite channel!!!"
now ive only been studying computer science/coding for a few months now and i am not very knowledgeable in this kinda stuff but your explanation actually made it fairly clear to someone with little coding experience.
3:46 I think, in the application the thing that separates the arguments from the environment variables is nothing. If you read after argc, you are in the environment variables space.
I think NULL is only used by execve to determine the number of arguments passed
There is no boundary in the memory where the actual strings are stored, but the argv array of pointers into that memory is terminated with a null pointer.
For me, the weirdest parts in here are:
1. Writing back to argv. That is usually a red alert.
2. Having a conversion executable with setuid bit set or capable of running as root.
I don't know about other exploits but this specific one wouldn't be one I'd ever end up doing.
Yeah I don't understand why the conversion module ever gets invoked with privileges... That just seems like an obvious exploit angle.
extremly nice video, just a minor technical detail: maybe a pop protection for you mic would be a nice addon :3
What's not clear to me is, if you set the first argument to NULL, shouldn't you still have another NULL to separate it from the environment variables?
From man page on `execve`:
"The argv array must be terminated by a NULL pointer."
Implies it's the programmer's job to terminate it with a null.
@@PwnFunction yes I then realized we were talking about execve and not running the program "normally"
I got confused because by talking about having NULL in argv[0] I was hearing that as setting the first argument to NULL, while we are not actually setting any argument at all
Lies again? Drink Carlsberg
@@NazriB 👍ok
Requiring programmers to pass the executable name again in the argument array is just as absurd as the day I learned that it is required
look at the white part on the penguin upside down
I didn't understand most of this, but it was engaging enough to distract my brain from anxiety while trying ro fall asleep. So thank you.
Me as a junior web dev watching this: “I can understand 9 words in that book”
I clicked this cause the title was interesting, but almost immediately clicked off of it thinking it would be over my head as someone with only novice level experience with any programming (VB in excel) or Linux. But this was actually well presented without overly dumbing it down to the point of making it boring.
It’s still a little bit over my head, but I got the gist of it.
Man I love your videos and explanations. Would you tell me what font are you using in terminal ?
Thanks! SF mono
first time watching ur videos and i already love it man, ur voice is calming and u explain coding stuff why better than my own teacher and if u were my teacher I would love to listen to u explain coding all day. keep up the amazing work man.
Who the heck writes setuid-type code with hacky stuff like writing to argv[n] etc.? This is code you need to be the most careful about...
as soon as I saw "argv[n] = path = s;" I had to wonder why on earth anybody would write to the arguments. As far as I'm aware, that's something nobody is supposed to do.
looks like the same guy that uses "goto"
@@gabrielpar3519 Goto bashing is so 1980! ;) Seriously - once compiled, there are gotos everywhere (JMP, JAL, JZ, JNZ,...). If used in the right scenario it can lead to more expressive code than avoiding it at any cost ever could.
@@bluesillybeard really because you are too lazy to create a new data storage for it. So you reuse the args.
@@gabrielpar3519 Goto is used a lot in C and kernel programming
OK, so this was in my recommended....have 0 idea what you're talking about, basically a foreign language, but I was hella invested!!
Thanks. I was having a difficulty understanding how this vulnerability would cause a problem from the explanation in the CVE.
Man, I need to get back into this. Did a stint with gov't contractor for an internship, we focused on a lot of this stuff. The biggest vulnerabilities we took advantage of in Linux is a general trust in modules, we could gain a lot of control of a system that way, just like with that control-mod you had.
This is an example of why you shouldn’t just think you’re absolutely safe because you use Linux.
Agreed, but at least we had the opportunity to find it.
People are delusional. It is never a matter of if only a matter of when.
@@LuminousWhispers11 and what, and why, and how...
You're never 100% safe. But this still doesn't change the fact that Linux is STILL very safe. Nevertheless people use BSD's for better security
True, though Linux basically hand over more tools for you to secure your machine against exploits like this such as AppArmor/SELinux which can restrict programs what they can do with root privilege. Windows equivalence is Mandatory Integrity Control which is pretty crap in comparison especially on Windows 11 which breaks everything.
Thank You for taking the time to explain this in legendary Detail. You Are Hero
I'm learning C right now so I didn't understand all of that but I really liked your explanation.
How was this vulnerability patched?
probably just checking the length of the list would fix it
Switch to a good language until it's too late
@Synth Depends on how you define a good language. People say JavaScript isn't a good language because it allows you to shoot yourself in the foot, well C allows you to freakin nuke your hometown. With great power comes great risks. Other languages will just give an API to access args and another for envs.
@Synth it's only capable of writing programs with vulnerabilities. even the most expricened dev can't deal with it
@Synth what about rust lol? Well that's a point not using such low level languages and rely to virtual machines. C doesn't even has smart pointers, absolute trash
I just came across this channel, its awesome! We want more vids!!!
Quite weird seeing this in recommended so soon after release for a channel that I've never interacted with before. But I'm game.
Same
Cool explanation. I used the berdav's exploit for this in a CTF about a month ago, worked like a charm.
_(I'd also recommend you include the CVE number in your title, it's sure to drive traffic/views.)_
"We set the first argument to NULL"
Did we? When did we do that?
I think this becomes clear when he shows the code of the exploit at 12:00. It's a bit surprising that execve allows argv[0] == null to be passed to the child process.
After 20 years of programming this is best code guide i have seen on exploits
Nice video, I thoroughly enjoyed it. One thing that was bothering me though: Why can't you just LD_PRELOAD over g_printerr and save yourself this GCONV business? When you talk about using LD_PRELOAD, and then saying there's a problem because clearenv() is called, I think you're actually missing the fundamental reason why LD_PRELOAD won't work here. LD_PRELOAD is processed before main() is executed (i.e., preloaded). This means we can't actually overwrite any functions because the env var doesn't exist at load, we only get to add env vars after loading. That's why GCONV is necessary here, because it gets processed during execution instead of only at load time.
Man.. Your content and explanations is just pure gold! Keep it up!
thanks for sharing this, excellent walk through.
"To qualify for the paranoia goldstar ..." - Writes the engineer who doesn't check for out-of-bounds accesses...
This world is rapidly passing away and I hope that you repent and take time to change before all out disaster occurs! Belief in messiah alone is not enough to grant you salvation - Matthew 7:21-23, John 3:3, John 3:36 (ESV is the best translation for John 3:36) if you believed in Messiah you would be following His commands as best as you could. If you are not a follower of Messiah I would highly recommend becoming one. Call on the name of Jesus and pray for Him to intervene in your life - Revelation 3:20.
Contemplate how the Roman Empire fulfilled the role of the beast from the sea in Revelation 13. Revelation 17 confirms that it is in fact Rome. From this we can conclude that A) Jesus is the Son of God and can predict the future or make it happen, B) The world leaders/nations/governments etc have been conspiring together for the last 3000+ years going back to Babylon and before, C) History as we know it is fake. You don't really need to speculate once you start a relationship with God.
Can't get a response from God? Fasting can help increase your perception and prayer can help initiate events. God will ignore you if your prayer does not align with His purpose (James 4:3) or if you are approaching Him when "unclean" (Isaiah 1:15, Isaiah 59:2, Micah 3:4). Stop eating food sacrificed to idols (McDonald's, Wendy's etc) stop glorifying yourself on social media or making other images of yourself (Second Commandment), stop gossiping about other people, stop watching obscene content etc. Have a blessed day!
One thing I don't understand is why the for loop is entered at all. If the first element of argv is NULL, then argc should be equal to 0, right?
**Edit:** nvm, the loop doesn't have to be entered at all for this to work.
Right. It has to create n and initialize it to 1 before it can compare it to anything. The comparison returns false so the body of the loop is not entered but n is still 1
Think I understood like 20% of this video... at best. But it was somehow still interesting enough to keep me till the end :D So that must be a good sign for you, Sir.
I know that we're technically allowed to modify the arguments in this way, and merely changing what argv points to isn't precisely wrong, but this is definitely some bad juju. While it would be less efficient, in this case I think safety should trump efficiency and it'd be better to just copy argv and modify your own copy.
That would break any program that modifies its own ``argv[0]`` to change its program name in `ps` and such.
@@szr8 It doesn't modify what shows up in 'ps', just what argv[0] points to. Remember, the array that is argv is on the stack. So everything it points to is considered read-only, but the pointers on the stack are not. You can't change argv[0][0], but you can change argv[0];
@@anon_y_mousse Afaics, the code here didn't change argv[1][0], just argv[1]. Same thing.
The problem is just that argv[1] is an alias for env[0] in this setup.
@@ccreutzig Actually, I just had a look at the code in question. Turns out it doesn't modify argv at all. I guess I should pay attention better. Apparently, the whole bug is in calling it with an empty argv, because it skips past argv[0] which when using exec*() like this can be empty. Moral of the story with this code, is don't expect that you're being called with your program name as argv[0]. Though, I stand by my statement that you should never modify argc and argv regardless of what you're doing.
@@ccreutzig Actually, disregard most of the previous comment too, I was looking at the updated code by mistake, and it does alter argv. However, the problem is that they expected argv[0] to point somewhere that it doesn't, and they didn't properly account for a 0 length argv.
i have 0 coding ability or a understanding of it. but you detail this so well me. good job!
After watching the video, i wondered why this is even possible in the first place, as the system calls setuid() and setgid() that you mentioned at 14:38 should already fail with "Permission denied". After looking around for a bit, I noticed the special user file permission "rws" instead of "rwx" for the program pkexec. Only because of the "s" flag pkexec is even allowed to call setuid() and setgid(), so any other preinstalled program with special file permissions will have the same vulnerability if not adressed in the code properly.
Considering the purpose of pkexec, it is obvious that it has the setuid bit set.
no way bro this has really helped me out in my school projects thank you for the amazing video
I have no idea what you're saying. It's like you're speaking another language but I still watched all the way
Such an underrated channel! Keep up the great content!
Just when you think your password was great you come in to find a user logged in without requiring a password and you are like.... how did you do that?
Yo, you are uploading so rapidly I can't keep up watching these videos
omg i love this guy so much
Damn I really enjoyed your video as a cybersecurity beginner! you explained it very clear! :)
Hey, quick question, if the first argument in argv is set to null, what is the value of argc? I would assume that it would be 0 or 1, but that's clearly not true
Edit to say that I messed around with this actual code some, and this does not run within the for loop, and that n is a global variable, so it doesn't exit scope before the invalid write is executed.
Yer, it's the usual problem of allowing a variable (n) to exist beyond the scope that it's needed for. If you really have to use globals, you need to do some sanity checking before you use them.
Pretty sure it is 0. The number of elements (including argv[0]) before the null value.
@@HenryLoenwind Indeed. I consider myself as an experienced C programmer and I was shocked to discover that argc can be 0. Using a 'for' or 'while' loop starting at index 1 is a pretty standard way to process arguments in C/C++. Pretty much any tutorial about argument processing in C is using such a loop. There are probably thousands of applications that could be abused in a similar way. Of course, most of them do not run setuid so that should not matter much (there are far easier ways to 'hack' a non-setuid program).
@@HenryLoenwind This is what I was figuring, I just did not realize that that value was set such that it existed outside of the loop
@@cynodont7391 Is it convention to do it with a global variable like what was done in this video? That's what seems to be the culprit here
I think i learnt more about arguments and how they are passing around than any exploit.
Still great content.
pkexec: Wait it's all BRUH?
sudo: Always has been.
i like how the vulnerable function is "to qualify for the paranoia goldstar ... avoid exploits" :P
I have an improvement suggestion: Please use dark mode in your code editor. It is very stressful for the eyes if the video switches between light and dark mode. Thank you 🙂
This is a great video. I'd appreciate a full diagram of the layout of argc and argv with pointers as well -- even if you don't wanna fully explain c string layout, just having a picture can be helpful. Like, have little squares showing character boundaries or something
Somehow... The original code also ought to raise red flags for being a bit too clever.
polkits needs to be rewritten in rust
Well said! Having to deal with too low-level implementation details together with the business logic makes us defocused and it's too easy to make mistakes.
bro these videos are not only entertaining but also educational
Question:
Did some one run a malicious app on a system to figure this out? From the explanation you gave, one would need to be at the given terminal for this exploit to work. But it was my understanding this was being triggered remotely. Did I miss something?
It's a privilage ESCALATION attack, meaning the system has already been breached or you have access already but as a low permision user and you are giving yourself better perms in order to do more detrimental things (like edit something you arent supposed to or view confidential information). A good example might be that you have remoted into a file sharing server and then as a guest on the server you run the code, get root, then add a new user to access everything with or maybe open a new reverse shell or smthn
the exploit has to be executed by the 'local' machine. That can be triggered remotely through ssh, since polkit is an exec you can reach without sudo. Not necessarily like you open an email and suddenly your system deletes itself. You gotta have a keyboard connection (like ssh) to execute this, or the user has to be tricked into executing it by hiding it in something like an app install executable.
as far as how did someone find out?
It was found by some nerds at a security company, so more than likely they spent a week looking through polkit's source out of curiousity and found this. Coordinated media release on jan 25th in order to give RedHat a 2 month warning
@@teal8365 Well it doesn't only have to be ssh or user error. You can also get a shell/terminal by using an attack what's known as a "reverse shell". Many languages include some way of opening up a child process or making an http request, which is vulnerable to exploitation
Not only terminal access, but the machine needs a desktop environment installed as well, because these packages don't install otherwise.. they are for popup password prompts, which are only on DEs. I manage many servers with many different distros and none of them have pkexec on them because they're all headless.
If your users don't have access to those prompts (which is pretty standard) you're already blocking access to this executable as well, so they couldn't even execute it.. so really right place right time type of exploit. There are many escalation attacks when you have this type of physical access.
@@gg-gn3re I found that too be the case with allot of exploits. The most dangerous place for them to be is right at the keyboard.
First video of yours I've seen, but loved it. Knew about the exploit (and of course updated my servers) but never really understood it under the hood. Crazy what we programmers can do when we don't know what we're doing! 🤪
This is why we really can't trust the 'many eyes' security philosophy of open source. Really nasty bugs like this are uncovered all the time even in Linux code, yet there are supposedly large numbers of programmers going through this stuff with a fine-toothed comb. Problem is there just aren't nearly enough programmers, particularly in packages maintained by just one or two people in practice. Even Linted code with lots of warnings makes it through quality control because people just aren't paid enough to care.
That's assuming this bug was not intentional on somebody's part. Who knows what inducements and/or persuasion is applied to those few who are meant to "insect" code for bugs?
@@YodaWhat Very good point, too.
And when we look at the numbers of discovered, exploitable bugs like this, we find that they're not much different to closed source software, and are sometimes worse, with worse effect because so many people use OSS.
Oh damn so that was the polkit vulnerability. Wow. Really good explanation. Thank you.
Windows users when there’s a security flaw: “THE END OF THE WORLD IS INEVITABLE WERE ALL GONNA DIE”
Linux users when there’s a security flaw: “pretty cool right?”
Great videos man, hope u upload more frequently
Best explanation
And I am in college I couldn't understand anything but still that was fun
5:20 The first one which jumped to my mind was, that the argument array is implicitly constant (yes, even if you don't state it), at least according to the language standard.
you need to increase the video sound.
why can't you?
@@ericxue3244 at max
@@crusader_ check your device, the video's fine
I have no idea what the hell he is talking about but he still finds a way to explain and make it interesting
I'm confused by one thing. Consider the expected case where argc > 0. The for loop goes
for (n = 1; n < (guint) argc; n++)
So at the end of this loop, we should have n == argc. Since nothing happens to n between here and this section
g_assert (argv[argc] == NULL);
path = g_strdup (argv[n]);
if (path == NULL)
It should be the case (especially with that assert) that argv[n] == NULL. So the next two lines just set path to NULL then check if it is, which doesn't make much sense to do. Am I missing something?
As explained in the video - what if argc is 0?
Presumable there's a "break" inside the loop, something like "if argv[n] == "--" /* end of parameter list marker */ break;"
Um, on second thought...: "if (argv[n] is not a flag) break;" is more likely.
Great explanation! Such a dangerous vulnerability hidden for all these years... Man, I wonder if someone had already exploited this in a regular way without disclosing it. Probably agencies LOL
thats basically a c vulnerability. Thankfully the linux ecosystem is moving to rust, where this wouldnt be possible. (In rust, if you request an element of an list that doesnt exist, the program crashes with an error message. )
Nah
@@gestaltengine6369 Please explain what you mean, because @SnakeMaster's argument seems totally legit to me.
Now you make me interested in programming,Gotta learn something from it
This is why we need to rewrite everything to Rust.
let's go a step further and rewrite everything in haskell. we need to go back to our roots
I'm just learning rust so I'm curious how rust would have prevented this error compared to c or even c++
@@askeladden450 Really depends on the exact code. Most likely, if you tried to write something very similar, you'd get a panic on the attempted out of bounds access. Though this is really not how you'd write this in Rust. 99.9% of the time you'd just use clap (or maybe some other proper arg parsing lib) or at the very least you wouldn't determine the length of the arguments by checking for a null pointer and similar weird stuff.
Realistically, this is something that pretty much every slightly higher level language would prevent. But Rust is one of the few languages that have low-level speed and access with the safety of a high-level language.
High level languages are great, but one sacrifices performance and excellent quality low level code by using them. You can't have your cake and eat it too. Saying just use this is or that high language doesn't solve this general problem. There is no substitute for putting in the labor for well designed, cross analyzed for weakness, and heavily tested code.
@@cetyl2626 "performance and excellent quality low level code" lmao try rust before making stereotypes.
this is definitely one of the videos in history!
damn, those c programmers really didn't care about stuff. Even my amateur code looks way more structured. And this is sudo-like software, sure THEY must've known a thing or two about privilege-escalation aren't they
No shit
It's pkexec. It's known lousy.
cant understand %80 of video but really like your telling style. I hope I will understand more and more
80%* 👍🏻
I mentioned Lennox ONCE, next day BAM this gets suggested to me by UA-cam. I know nothing of Lennox. I have never looked up anything like this. WoOoOOOOoO spoopyyy
Your voice makes me want to rip my pillow in half
I was gonna subscribe once the video was over bc it was incredible, but I subscribed immediately after seeing BRUH lmfao