5 ms·
Fixing a Buffer Overflow in Unix v4 Like It's 1973
- mgerdts 9mo agoWhat is up with fin? Is it really just writing an int 0 in the memory right after some variable present in libc or similar? extern fin; if(getpw(0, pwbuf)) goto badpw; (&fin)[1] = 0;
- flatline 9mo agoAccording to the chatbot, the first word of `fin` is the file descriptor, the second its state. "Reset stdin’s flags to a clean state".
- oguz-ismail2 9mo agoPredecessor of extern FILE *stdin;
- formerly_proven 9mo agoI’m guessing v4 C didn’t have structs yet (v6 C does, but struct members are actually in the global namespace and are basically just sugar for offset and a type cast; member access even worked on literals. That’s why structs from early unix APIs have prefixed member names, like st_mode.
- Boltgolt 9mo ago)
- jacquesm 9mo agoHeh. I had the same impulse but then didn't do it, upon refreshing the page your comment was there :)
- topspin 9mo ago> I’m guessing v4 C didn’t have structs yet There may have been a early C without structs (B had none,) but according to Ken Thompson, the addition of structs to C was an important change, and a reason why his third attempt rewrite UNIX from assembly to a portable language finally succeeded. Certainly by the time the recently recovered v4 tape was made, C had structs: ~/unix_v4$ cat usr/sys/proc.h struct proc { char p_stat; char p_flag; char p_pri; char p_sig; char p_null; char p_time; int p_ttyp; int p_pid; int p_ppid; int p_addr; int p_size; int p_wchan; int *p_textp; } proc[NPROC]; /* stat codes */ #define SSLEEP 1 #define SWAIT 2 #define SRUN 3 #define SIDL 4 #define SZOMB 5 /* flag codes */ #define SLOAD 01 #define SSYS 02 #define SLOCK 04 #define SSWAP 010
- b-kuiper 9mo agoso, is there already somebody that wrote the exploit for it? are there any special things to consider exploiting such architecture back in the day or do the same basic principles apply?
- b-kuiper 9mo agoEDIT: removed due to low effort and mark-up issues. thank you all for your feedback.
- b-kuiper 9mo agoperhaps the downvoters can tell me why they are downvoting? i'm curious to hear whether if this would work on unix v4 or whether there are special things to consider. I thought i would ask claude for a basic example so people could perhaps provide feedback. i guess people consider it low effort reply? anyway, thanks for your input.
- csnover 9mo agoYour response is a non-sequitur that does not answer the question you yourself posed, and you are responding to yourself with a chatbot. Given that it is a non-sequitur, presumably it is also the case that no work was done to verify whether the output of the LLM was hallucinated or not, so it is probably also wrong in some way. LLMs are token predictors, not fact databases; the idea that it would be reproducing a “historical exploit” is nonsensical. Do you believe what it says because it says so in a code comment? Please remember what LLMs are actually doing and set your expectations accordingly. More generally, people don’t participate in communities to have conversations with someone else’s chatbot, and especially not to have to vicariously read someone else’s own conversation with their own chatbot.
- AgentME 9mo agoThe explanation it gives at the start appears to be on the right track but then the post has two separate incomplete/flawed attempts at coding it. (The first one doesn't actually put the expected crypt() output in the payload, and the second one puts null bytes in the password section of the payload where they can't go.)
- ChrisArchitect 9mo agoRelated: An initial analysis of the discovered Unix V4 tape https://news.ycombinator.com/item?id=46367744 https://news.ycombinator.com/item?id=46367744 Unix v4 (1973) – Live Terminal https://news.ycombinator.com/item?id=46468283 https://news.ycombinator.com/item?id=46468283
- nineteen999 9mo agoAlready patched this on my x86_64 v4 UNIX port. Hehe.
- retrac 9mo ago> x86_64 v4 UNIX port What compiler are you using?
- nineteen999 9mo agogcc. Im also working on a port of the original compiler, but that's a much lower priority for me.
- nullpoint420 9mo agoThat sounds really fun!
- SoftTalker 9mo agoI had to use ed once in a very limited recovery situation. I don't remember the details but even vi was not an option. It's not terrible if you just need to change a few lines. Using it on a teletype to write code all day would get tedious quickly. Full-screen editors had to have been an amazing productivity boost.
- fooker 9mo agoThe amount of code was relatively low. Not the million line codebases we have today. 50-100 lines was the usual program or script.
- avadodin 9mo agoiirc they were initially using actual ttys(as in typewriters) and the input delay was hell which is the reason so many UNIX commands are two letters. So likely they would work on the printout: 1,$n And then input the corrections into ed(1).
- fooker 9mo agoThat was one generation before this. In unix v4 times, input latency was in the order of ~100ms, basically limited by the serial port. Pretty advanced terminals were starting to show up too - https://en.wikipedia.org/wiki/VT100 https://en.wikipedia.org/wiki/VT100
- deleted 9mo ago[deleted]
- irusensei 9mo agoI had to use it when I installed 9front on a computer that has no graphics card just a serial port (APU2C2). I had only a serial device at 9600bps and the other text editors (sam, acme) didn't worked. I wanted to turn it into a CPU server so I can use drawterm to access it remotely and that requires editing a few files.
- b00ty4breakfast 9mo ago
- kazinator 9mo agoRemotely exploiting a buffer overflow in Unix like it's 1973. # ... sound of crickets ... Wanna see me do it again?
- nineteen999 9mo agoRemotely? ... this version of UNIX doesn't have any networking.
- w-m 9mo agoThe password and pwbuf arrays are declared one right after the other. Will they appear consecutive in memory, i.e. will you overwrite pwbuf when writing past password? If so, could you type the same password that’s exactly 100 bytes twice and then hit enter to gain root? With only clobbering one additional byte, of ttybuf? Edit: no, silly, password is overwritten with its hash before the comparison.
- loeg 9mo ago> will you overwrite pwbuf when writing past password? Right. > If so, could you type the same password that’s exactly 100 bytes twice and then hit enter to gain root? With only clobbering one additional byte, of ttybuf? Almost. You need to type crypt(password) in the part that overflows to pwbuf.
- deleted 9mo ago[deleted]
- asveikau 9mo agoA bit of a code review (some details from the patch removed for clarity): + register int i; q = password; - while((*q = getchar()) != '\n') + i = 0; + while((*q = getchar()) != '\n') { + if (++i >= sizeof(password)) + goto error; You don't actually need i here. i is the same as (q - password). It would be idiomatic C to simply rewrite the loop condition as: while (q < password+sizeof(password) && (*q = getchar()) != '\n'). To preserve your "goto error;" part, maybe you could do the overflow check when null terminating outside the loop.
- shakna 9mo agoIsn't sizeof only standardised in C89? Wouldn't shock me if this form needs to be an rvalue. The author did try pointer arithmetic: > I initially attempted a fix using pointer arithmetic, but the 1973 C compiler didn’t like it, while it didn’t refuse the syntax, the code had no effect.
- asveikau 9mo agoThis surprised me too. The snippet I was quoting from was already using sizeof, though. I missed the blurb about pointer arithmetic. Would be interesting to go into detail about what "had no effect" means.
- VonTum 9mo agoThe article specifically mentions this optimization as not working with the compiler at that time, hence the need for the separate index variable. > We will edit su.c to prevent the overflow by maintaining a counter, i, and verifying it against the buffer size during the read loop. I initially attempted a fix using pointer arithmetic, but the 1973 C compiler didn’t like it, while it didn’t refuse the syntax, the code had no effect. I settled on a simpler index-based check instead.
- asveikau 9mo agoYour sibling comment mentions it. There's no details.. why didn't it work? Maybe the author didn't write it correctly? No word on what the assembly output for it was...
- WalterBright 9mo agoHaving a buffer with a fixed size is always a red flag for further checking.
- WalterBright 9mo agoBack in the 80s, when I was writing a C compiler, C compilers typically had a maximum size for string literals. The behavior was to detect overflow, issue an error message, and fail compilation. I took a different tack. The buffer was allocated with malloc. When a string was larger, it was realloced to a larger size. This worked until memory was exhausted, and then the program quit. It was actually less code to implement than having a fixed size buffer. Ditto for the other compilation limits, such as length of a line. The only limit was running out of memory.
- emilfihlman 9mo agoThe source has ttybuf[2] =& ~010; Which is another bug.
- messe 9mo agoWhat's the bug? If you're referring to the =& syntax, then that's just how &= used to be written in older versions of C.
- serpent 9mo agoAre you sure any buffer overflows were actually fixed in 1973?