Live data from Hacker News

Local privilege escalation via execve()

freebsd.org

101–110 of 116 posts

Re: Local privilege escalation via execve()

#101
post #97
post #28

Nice to randomly encounter our own work here. Check out our blog post for a fun walkthrough: https://blog.calif.io/p/cve-2026-7270-how-i-get-root-on-free... AI-generated working exploit, write-up and prompts: https://github.com/califio/publications/tree/main/MADBugs/fr...

"our" is a stretch. Not only because you're giving an algorithm personhood, but because you didn't do any of the real work. So you could instead say that it's "nice to randomly encounter what I prompted an instance of [brand of artificially intelligent dowsing rod] to do". There's your chance to claim ownership; you can plainly state that you're the person who pressed the button.

They are fixing bugs in open source projects. What are you doing? You're not even tapping that button.

Re: Local privilege escalation via execve()

#102

memmove(args->begin_argv + extend, args->begin_argv + consume, args->endp - args->begin_argv + consume); // ← bug C code like this is why we can't have nice things. Arithmetic operation in the arguments of a dangerous function call with no explicit bounds check.

[flagged]

Re: Local privilege escalation via execve()

#103
post #65

- args->endp - args->begin_argv + consume); + args->endp - (args->begin_argv + consume)); tbh I've considered simply banning math-operator-precedence in projects I work on, and requiring all mixed-operator code to use parenthesis or split to multiple statements. I do that myself, at least. I've seen so many mistakes from it, and seen people spend so much pointless and avoidable time deciphering and verifying it, it r…

I once had a job interview where they wanted to evaluate my C knowledge. They showed me a printout of some pointer arithmetic and said spot the bug. (It may actually have been the old puzzle where it turns out that /* is always a comment opener and never a division by the referent of a pointer). I said "well first, this is a mess, I'm putting parentheses here, here, here and here". They said "well you've fixed the bu…

> I gave them a hypothesis but I said my "real answer" was that it's not worth our brain cycles to figure it out, you just shouldn't write code that requires knowing operator precedence. It's just such desperately boring information that I can't hold it in my head.

this is exactly how I think. and it goes for a lot of stuff in general, we have limited bandwidth and wasting it on useless stuff like this has no real purpose.

yet sometimes I see people show off about how they know how to deal with it but I just don't see the point.

Re: Local privilege escalation via execve()

#104

Earlier quoted context omitted.

I agree with explicit parentheses but please be careful about assuming associativity! The risk when handling floating-point arithmetic in particular is that associativity breaks, and suddenly a + (b + c) does NOT equal (a + b) + c. Not only can these lead to unexpected and hard-to-trace failure patterns, but depending on the details, they also can introduce memory overflow/underflow vulnerabilities.

If you're going for bit-for-bit equivalence of float values, then even with a single operation you're relying on compiler flags, architecture, the phase of the moon... I'm hard-pressed to think of any memory safety issues though.

Yea, you're in a fairly special niche of programming if you're somewhere that truly matters, and you can't accept any valid order's output. In most general code, if that kind of precision matters, float is the wrong choice: use a bignum object and be exactly correct regardless of how you organized your code.

Which is a niche that exists, obviously. So it is absolutely true for some cases. But I would hope that any code that requires this is extremely clear about requiring it.

Re: Local privilege escalation via execve()

#105
post #65

- args->endp - args->begin_argv + consume); + args->endp - (args->begin_argv + consume)); tbh I've considered simply banning math-operator-precedence in projects I work on, and requiring all mixed-operator code to use parenthesis or split to multiple statements. I do that myself, at least. I've seen so many mistakes from it, and seen people spend so much pointless and avoidable time deciphering and verifying it, it r…

I've also grown somewhat sensitive to duplication, maybe to a painful level. But, the memmove-call from the AI writeup has duplication in there:

    memmove(args->begin_argv + extend,
            args->begin_argv + consume,
            args->endp - args->begin_argv + consume);   // ← bug
If both `args->begin_argv + consume` are supposed to be the same concept and thus the same value, I'd have a variable for it by now. Some people hate it with a passion, but something like this removes the precendence thinking, prevents modification of one and not the other and makes it easier to follow, for me at least:

    retained_tail_begin = args->begin_argv + consume
    memmove(args->begin_argv + extend,
            retained_tail_begin,
            args->endp - retained_tail_begin);
Though at that point one might also encode the entire intent (as far as I understand it) in variables as well:

    space_to_replace_end = args->begin_argv + extend
    retained_tail_begin = args->begin_argv + consume
    memmove(space_to_replace_end,
            retained_tail_begin,
            args->endp - retained_tail_begin);
Sure we can golf the names somewhat, but that code has my head spin a lot less about math and precedence.

Re: Local privilege escalation via execve()

#106
post #105
post #65

- args->endp - args->begin_argv + consume); + args->endp - (args->begin_argv + consume)); tbh I've considered simply banning math-operator-precedence in projects I work on, and requiring all mixed-operator code to use parenthesis or split to multiple statements. I do that myself, at least. I've seen so many mistakes from it, and seen people spend so much pointless and avoidable time deciphering and verifying it, it r…

I've also grown somewhat sensitive to duplication, maybe to a painful level. But, the memmove-call from the AI writeup has duplication in there: memmove(args->begin_argv + extend, args->begin_argv + consume, args->endp - args->begin_argv + consume); // ← bug If both `args->begin_argv + consume` are supposed to be the same concept and thus the same value, I'd have a variable for it by now. Some people hate it with a p…

Yeah - sharing a variable there is a pretty strong signal that they are the same concept and can't be allowed to be different, not just "maybe the same value". That's useful to know.

If there's a ton of it in a dense bit of code, 1) it might be too complex, try making it clearer, and 2) it unfortunately makes for a lot of indirection and that can make it harder to follow, which is generally why I see people dislike it. In non-critical code I can kinda agree with inlining it. Pointer arithmetic is imo never non-trivial tho, paranoia is warranted. Especially in a kernel.

Re: Local privilege escalation via execve()

#107
post #54

Earlier quoted context omitted.

I just read that it was spilling into argv or something and assumed the vector was somehow injecting arguments or something.

The exploit is injecting environment variables, but yes, close enough. You need someone to call execve as root in order to become root, but you don't need a setuid binary.

I am reading:

"When the timing aligns, the trigger's buggy memmove causes K+1 to self-overwrite, replacing sshd-session's real environment with the preseed payload. sshd-session's exec_copyout_strings copies LD_PRELOAD=/tmp/evil.so to the new process's stack, the runtime linker loads evil.so, and its constructor copies /bin/sh to /tmp/rootsh and sets it suid root. My human's unprivileged user runs /tmp/rootsh -p and gets a root shell."

... so at the very end of the exploit chain, is /tmp/rootsh required to be suid root before it is finally run to get the root shell ?

... or is the exploit already achieved and /tmp/rootsh is just an arbitrary indicator ?

Re: Local privilege escalation via execve()

#108
post #107

Earlier quoted context omitted.

The exploit is injecting environment variables, but yes, close enough. You need someone to call execve as root in order to become root, but you don't need a setuid binary.

I am reading: "When the timing aligns, the trigger's buggy memmove causes K+1 to self-overwrite, replacing sshd-session's real environment with the preseed payload. sshd-session's exec_copyout_strings copies LD_PRELOAD=/tmp/evil.so to the new process's stack, the runtime linker loads evil.so, and its constructor copies /bin/sh to /tmp/rootsh and sets it suid root. My human's unprivileged user runs /tmp/rootsh -p and…

One of the authors is on this subthread correcting me. :)

Re: Local privilege escalation via execve()

#109
post #65

- args->endp - args->begin_argv + consume); + args->endp - (args->begin_argv + consume)); tbh I've considered simply banning math-operator-precedence in projects I work on, and requiring all mixed-operator code to use parenthesis or split to multiple statements. I do that myself, at least. I've seen so many mistakes from it, and seen people spend so much pointless and avoidable time deciphering and verifying it, it r…

I once had a job interview where they wanted to evaluate my C knowledge. They showed me a printout of some pointer arithmetic and said spot the bug. (It may actually have been the old puzzle where it turns out that /* is always a comment opener and never a division by the referent of a pointer). I said "well first, this is a mess, I'm putting parentheses here, here, here and here". They said "well you've fixed the bu…

Your response was more correct in a professional sense than producing the piece of knowledge you've been asked for. I'd prefer to work with people who value everyone's time and write programs accordingly. If the interviewer was looking for a valuable expert, they were lucky to get you on board.

Re: Local privilege escalation via execve()

#110
post #107

Earlier quoted context omitted.

The exploit is injecting environment variables, but yes, close enough. You need someone to call execve as root in order to become root, but you don't need a setuid binary.

I am reading: "When the timing aligns, the trigger's buggy memmove causes K+1 to self-overwrite, replacing sshd-session's real environment with the preseed payload. sshd-session's exec_copyout_strings copies LD_PRELOAD=/tmp/evil.so to the new process's stack, the runtime linker loads evil.so, and its constructor copies /bin/sh to /tmp/rootsh and sets it suid root. My human's unprivileged user runs /tmp/rootsh -p and…

The exploit already succeeded at that point, creating the setuid /tmp/rootsh is just a way of making it permanent.
Post reply on HN