Renamed all README.DK.md files to README.DA.md.
This commit is contained in:
parent
21ee05cecd
commit
c366f104f0
3 changed files with 0 additions and 0 deletions
|
|
@ -1,309 +0,0 @@
|
|||
# `wosuid`-laboratoriet — root-RCE **uden** setuid-bit
|
||||
|
||||
```
|
||||
foowosd en bevidst sårbar daemon, der er root, fordi den blev *STARTET* som
|
||||
root (port 2344, kun loopback som standard)
|
||||
foowosc exploitet: forvandler et stack-overløb til en **root**-shell ved at
|
||||
udføre shellcode — de samme 23 bytes, der knækkede user-level-
|
||||
`food`-daemonen i det overordnede laboratorium
|
||||
```
|
||||
|
||||
Det er det tredje laboratorium i serien. Samme exploit-værktøjskæde, samme
|
||||
stil, én fundamental forskel:
|
||||
|
||||
| Laboratorium | hvordan target-processen bliver root | `uid=0(root)`-shell? |
|
||||
|----------|------------------------------------------------|----------------------|
|
||||
| food/fooc| aldrig — det er en almindelig user-daemon | nej |
|
||||
| foosd/foosc | SUID-bitten (`chmod u+s`) — euid 0, ruid 1000 | ja (kræver `setreuid` i shellcoden, fordi bash nulstiller euid→ruid) |
|
||||
| **foowosd/foowosc** | **ingen — root *starter* daemonen** (sudo / systemd `User=root`) | **ja (almindelig `execve`-shellcode)** |
|
||||
|
||||
Setuid-bitten er et *transportmiddel* for privilegier — ikke privilegierne
|
||||
selv. En daemon startet af root har reelle, effektive og gemte uid alle lig 0.
|
||||
For kernen er det root, punktum; den kan og vil ikke vide, om processen kom
|
||||
derhen via `+s` på en fil eller via `sudo ./foowosd`. Overløbet i en
|
||||
root-started daemon er altså et root-exploit — *"jeg har ingen
|
||||
SUID-binærfiler" er ikke det samme som "jeg er ikke udnyttelig".*
|
||||
|
||||
Det er hele lektionen i dette laboratorium. Alt herunder er maskineriet.
|
||||
|
||||
---
|
||||
|
||||
## Hurtig start (hvad brugeren bad om)
|
||||
|
||||
```
|
||||
cd wosuid
|
||||
make # bygger daemonen, exploitet og test-harnessen
|
||||
```
|
||||
|
||||
### Det ægte — kør daemonen som **root**
|
||||
|
||||
```
|
||||
sudo make run-root # starter foowosd som uid 0 (proces, ikke filtilstand)
|
||||
make test-root # hver teknik skal nu give uid=0(root)
|
||||
```
|
||||
|
||||
### Ikke sudo? Den identiske kernel-sti via en user-namespace
|
||||
|
||||
```
|
||||
make run-root-ns # uid 0 i en user-namespace — ingen adgangskode nødvendig
|
||||
make test-root # samme domme; bruges af CI og alle uden sudo
|
||||
```
|
||||
|
||||
### Baseline — daemon som din normale bruger (intet root nogen steder)
|
||||
|
||||
```
|
||||
make run # foowosd kører med dine uider
|
||||
make test # exploits lander shells, men `root` forventes MISSING
|
||||
```
|
||||
|
||||
### Oprydningsritual (altid: dette er et root-shell-laboratorium)
|
||||
|
||||
```
|
||||
make stop
|
||||
```
|
||||
|
||||
`foowosd` er *ikke* setuid, og intet i dette bibliotek laver nogensinde
|
||||
`chmod +s` — det er pointen. Den farlige tilstand er **processen**, ikke
|
||||
filen.
|
||||
|
||||
---
|
||||
|
||||
## Når du bliver bedt om at sætte SUID-bitten
|
||||
|
||||
Det kommer du **ikke** til. Dette laboratorium har bevidst ingen SUID-bit:
|
||||
|
||||
- `foowosd` bygges, ejes og har almindelige tilstande som ethvert andet program.
|
||||
- Det bliver root, som rigtige daemoner gør — ved at blive *startet* af root.
|
||||
- `make run-root` bruger `sudo` til præcis det, og `make run-root-ns` får en
|
||||
ægte uid-0-proces helt uden noget af det.
|
||||
|
||||
Suid-bitten tilhører *søster*-laboratoriet (`foosd`). Kontrasten mellem de to
|
||||
er pensum:
|
||||
|
||||
1. SUID-laboratoriet: bitten giver **euid 0, men ruid 1000** →
|
||||
`execve("/bin/sh")` nedgraderes af bashs vagt (`euid != ruid` → reset) →
|
||||
shellcoden må først kalde `setreuid(0,0)` (32-byte-payload).
|
||||
2. Dette laboratorium: root **starter** processen → **ruid == euid == 0** →
|
||||
vagten har intet at nulstille → den almindelige 23-byte `execve`-shellcode
|
||||
beholder root.
|
||||
|
||||
Samme overløb. Samme teknik. Forskellig *oprindelse* af privilegier, anderledes
|
||||
payload-form. Det er lektionen i miniature.
|
||||
|
||||
---
|
||||
|
||||
## Protokollen
|
||||
|
||||
Uanset hvilken slags klient der forbinder, hilser foowosd på den med:
|
||||
|
||||
```
|
||||
FOOWOSD 1.0 ids=0/0 leak stack=0x7ffd… libc=0x7f… (banneret + leaks)
|
||||
BUF=0x7ffd… (bufferadressen)
|
||||
```
|
||||
|
||||
`ids=euid/ruid` er *"er jeg root?"*-sidekanalen. foowosc printer en høj
|
||||
advarsel, når euid ikke er 0 (dvs. du startede daemonen som en almindelig
|
||||
bruger): payloaden lander stadig, men shellen bliver en bruger-shell, og at
|
||||
kalde exploitet "i stykker" ville være forkert — det eskalerer bare ikke.
|
||||
|
||||
> Staveform-bemærkning: `ids=`, ikke `euid=`/`ruid=`. Test-harnessen beviser et
|
||||
> levende `id` ved at matche den bogstavelige form `uid=NNN(`, så banneret må
|
||||
> aldrig indeholde en delstreng, der selv opfylder tjekket. (I SUID-laboratoriet
|
||||
> producerede præcis den fælde et spektakulært falsk positivt.)
|
||||
|
||||
---
|
||||
|
||||
## Exploit-teknikkerne (`foowosc -t …`)
|
||||
|
||||
Alle fire exploit-stier nedenfor virker mod foowosd. Når daemonen er root,
|
||||
giver **alle, der spawner noget, root** — i modsætning til SUID-laboratoriet,
|
||||
hvor ret2win/ret2libc stille og roligt blev nedgraderet til uid 1000 af bashs
|
||||
vagt. Her er der intet mismatch at vogte mod.
|
||||
|
||||
| `-t` | hvad der sker | når daemonen er root |
|
||||
|---------------|---------------------------------------------------------------------|---------------------|
|
||||
| `shellcode` | 23-byte-`execve("/bin/sh", NULL, NULL)` kører på stacken. | **root-shell** (standard) |
|
||||
| `ret2win` | hop til `win()` → `execl("/bin/sh")` | **root-shell** |
|
||||
| `ret2libc` | ROP: `pop rdi; ret` → `"/bin/sh"` → `system()` | **root-shell** |
|
||||
| `demo` | kun junk-overløb — forvent et SIGSEGV i daemon-loggen | nedbrud, efter design |
|
||||
| `leak` | printer bare leaks, sender ingen payload | n/a |
|
||||
|
||||
```
|
||||
./foowosc -t shellcode # interaktiv; standard-target 127.0.0.1:2344
|
||||
./foowosc -t shellcode -n # send og rapporter, ingen interaktiv session
|
||||
```
|
||||
|
||||
En vellykket interaktiv session videresender din terminal til shellen *på
|
||||
offeret* — der er præcis én shell i billedet, og det er `/bin/sh`, der kører
|
||||
som root inde i foowosd. Skriv `id` for at se `uid=0(root)`.
|
||||
|
||||
### Hvorfor der ikke er nogen `ret2win-root`-teknik her
|
||||
|
||||
foosc havde én — den hoppede til et `win_root()`, der kaldte `setreuid(0,0)`
|
||||
før exec, fordi en setuid-proces kørte med en reelle uid, der stadig sagde
|
||||
1000. En root-*startet* proces har den reelle uid allerede 0; der er intet at
|
||||
rydde, så den ekstra funktion og teknik ville ikke lære noget. Fjernet.
|
||||
|
||||
---
|
||||
|
||||
## Hvad foowosc gør, trin for trin
|
||||
|
||||
1. **Statisk analyse** — `objdump -d` af `./foowosd`. Finder
|
||||
`vulnerable_handler`, `win()`, det `lea -0x50(%rbp)`, der adresserer `buf`,
|
||||
og det første nøgne `ret`. Ud fra forskydningen beregner det
|
||||
`rip_off = 80 + 8 = 88`. Intet er hardkodet; det overlever en genbygning.
|
||||
2. **Selv-introspektion** — læser sit eget `/proc/self/maps` og `dlsym()`er
|
||||
`system`/`read` for at lære libc-*offsets*. Targetets libc-base er
|
||||
`leaked_read − off_read`, derefter `system = base + off_system`, osv. Denne
|
||||
delta-aritmetik er grunden til, at exploits overlever libc-versioner.
|
||||
3. **Forbind** — læser banneret/leaks (`ids=`, `stack=`, `libc=`, `BUF=`).
|
||||
4. **Byg payloaden** — for `shellcode`: 23 bytes maskinkode, padding til
|
||||
`rip_off`, derefter den gemte RIP = `buf` (så `ret` hopper ind på koden). For
|
||||
`ret2win`/`ret2libc`: adresser beregnet ud fra analysen — ingen udførelse af
|
||||
stacken nødvendig.
|
||||
5. **Justeringsfixen** — et kapret nøgent `ret` giver callee'en
|
||||
`rsp ≡ 8 (mod 16)`, og glibcs SSE2-kode `movaps`-fault'er på en ikke-justeret
|
||||
stack (crash-reporteren logger `si_addr=(nil)` — fingerpeget). foowosc
|
||||
indsætter ét ekstra `ret`-gadget før det rigtige target og genopretter
|
||||
invarianten. Silkehandsketeknik i et shellcode-laboratorium, men det er
|
||||
forskellen mellem en payload, der "nogle gange virker", og en, der altid
|
||||
virker.
|
||||
6. **Send, derefter videresend** — offerprocessen *er* shellen; denne proces
|
||||
splisser kun bytes. Ingen lokal shell, ingen anden læser — single-read-
|
||||
cursor-fejlen (ét spist byte per chunk) er dokumenteret i `become_shell()`.
|
||||
|
||||
---
|
||||
|
||||
## Daemonens bevidste fejl (alle i `foowosd.c`, alle ægte CWE-klasser)
|
||||
|
||||
| # | fejl | CWE | note |
|
||||
|---|-----|-----|------|
|
||||
| 1 | `read(fd, buf, 512)` ind i et 64-byte stack-buffer | [CWE-120](https://cwe.mitre.org/data/definitions/120.html) | overløbet: 448 bytes forbi `buf`, gemt RIP ved +88 |
|
||||
| 2 | kun `snprintf(line, …, "%.*s", …)`; men angriber-`%` i echo-stien | [CWE-134](https://cwe.mitre.org/data/definitions/134.html) | leaket er her den reelle payload; et `%n` i en *root*-proces ville være write-what-where som root |
|
||||
| 3 | børn beholder root, mens de håndterer utroverdige inputs | [CWE-271](https://cwe.mitre.org/data/definitions/271.html) | det korrekte `drop_privs()` (setgroups→setgid→setuid, i den rækkefølge, med verifikation) står i filen, kommenteret, *bevidst aldrig kaldt* |
|
||||
| 4 | `ids=`, `stack=`, `libc=`, `BUF=` afsløret til enhver klient | [CWE-200](https://cwe.mitre.org/data/definitions/200.html) | uden disse leaks kunne shellcode- og ret2libc-teknikkerne ikke beregne adresser (ASLR ville besejre dem) |
|
||||
|
||||
Handleren har præcis samme `buf[64]`/`read(512)`-form som de to andre
|
||||
laboratorier, så den fælles objdump-baserede erkendelsespipeline virker
|
||||
uændret.
|
||||
|
||||
---
|
||||
|
||||
## Sådan inspicerer du daemonen (læringssti)
|
||||
|
||||
```
|
||||
make status # kører den? som hvilken uid? filtilsand vises
|
||||
make run-root # eller run / run-root-ns
|
||||
./foowosc -t leak # se banneret og leaks, send intet
|
||||
./foowosc -t demo # junk-overløb -> SIGSEGV, logget med RIP/rsp
|
||||
./foowosc -t shellcode # den interaktive root-shell
|
||||
make test-root # fuld matrix, alle teknikker, --must-root
|
||||
```
|
||||
|
||||
Crash-reporter: Ved SIGSEGV logger daemonen fejladressen, RIP og RSP. Et `ret`
|
||||
ind i en ikke-kanonisk `0x4141…` fault'er ved `ret`-et selv (RIP som `0x4028xx`,
|
||||
`si_addr=(nil)`) — værd at vide, før du fejllæser en loglinje som en
|
||||
NULL-dereference.
|
||||
|
||||
---
|
||||
|
||||
## Hvorfor shellcoden er 23 bytes, ikke 32
|
||||
|
||||
```
|
||||
31 f6 xor esi, esi ; argv = NULL
|
||||
31 d2 xor edx, edx ; envp = NULL
|
||||
48 bf 2f62696e2f736800 movabs rdi, "/bin/sh\0"
|
||||
57 push rdi
|
||||
48 89 e7 mov rdi, rsp
|
||||
6a 3b push 0x3b ; 59 = execve
|
||||
58 pop rax
|
||||
0f 05 syscall
|
||||
```
|
||||
|
||||
SUID-laboratoriet har brug for `setreuid(0,0)` foran dette. Dette
|
||||
laboratorium ikke, af den grund der gentages overalt: **ruid er allerede 0**,
|
||||
fordi root startede processen. `make verify` beviser, at bytes i `foowosc.c`
|
||||
er byte-for-byte det, `shellcode.S` assemblerer til.
|
||||
|
||||
---
|
||||
|
||||
## Modforanstaltninger — hvad `make hardened` ændrer
|
||||
|
||||
Hærdet build (`-fstack-protector-strong -fPIE -pie -z noexecstack`):
|
||||
|
||||
| teknik | sårbar `foowosd` | hærdet `foowosd_hardened` |
|
||||
|-----------|----------------------|------------------------------|
|
||||
| `shellcode` | root-shell (eksekverbar stack) | SIGSEGV ved canary-tjekket / NX |
|
||||
| `ret2win` / `ret2libc` | root-shell | canary abort'er `ret` — men bemærk: en *PIE*-build gør også disse adresser tilfældige |
|
||||
| `demo` | SIGSEGV, logget | SIGSEGV, logget |
|
||||
|
||||
`make test-hardened` demonstrerer det live. Den vigtige observation er ikke
|
||||
bare, at modforanstaltningerne dræbte teknikkerne — det er, at de **ikke**
|
||||
gjorde daemonen til "ikke-root". En hærdet build, der stadig *startes* som
|
||||
root, er stadig en root-daemon; modforanstaltningen hæver kun barren for
|
||||
angriberen. Least privilege (`drop_privs()`) og hukommelsessikkerhed er to
|
||||
forskellige fejl, og en daemon, der ikke behøver root, bør ikke have det.
|
||||
|
||||
---
|
||||
|
||||
## Sikkerhedsgelændere (samme politik som SUID-laboratoriet)
|
||||
|
||||
- **Kun loopback.** foowosd nægter at binde andet end `127.0.0.1` /
|
||||
`localhost` / `::1`, medmindre du giver `-L`. En root-daemon på en rigtig
|
||||
grænseflade er en *fjern* root-tjeneste. `-L` findes kun for at vise vagten;
|
||||
brug den ikke på noget, der betyder noget.
|
||||
- **Tilstanden logges højt.** Ved start printer den `ruid/euid` og om dette er
|
||||
en root-proces, så du altid ved, hvilket exploit-resultat du skal forvente.
|
||||
- **Domme kommer fra exit-status** i `make test*` (pty-harnessens
|
||||
returkode), aldrig fra at greppe dens stdout — grebbart output lyver.
|
||||
- **pty'en skal køre cooked + ECHO off**, ellers ekkoer harnessen sin egen
|
||||
kommandolinje og forfalsker markøren. Harnessen slår ECHO fra og beholder
|
||||
ECHONL på.
|
||||
- **Oprydningsritual:** `make stop` efter hver session. Hvis daemonen er
|
||||
root-ejet, siger `stop` dig at køre `sudo pkill -x foowosd`.
|
||||
- Kør aldrig dette på en host, du holder af. Det findes for at uddele
|
||||
`uid=0`-shells over loopback-grænsefladen.
|
||||
|
||||
---
|
||||
|
||||
## Øvelser
|
||||
|
||||
1. Kør `make run` (user-daemon), derefter `./foowosc -t shellcode`. Hvorfor er
|
||||
shellen ikke root? (Tjek `ids=` i banneret — foowosc siger dig det, før du
|
||||
overhovedet forbinder.)
|
||||
2. `make stop && sudo make run-root && make test-root`. Forklar ud fra
|
||||
bannerlinjen, hvorfor alle fire teknikker nu giver `uid=0(root)`.
|
||||
3. Find i `foowosd.c` `drop_privs()` og læs, *hvorfor rækkefølgen* af
|
||||
`setgroups → setgid → setuid` betyder noget. Beslut, hvor i `main()` den
|
||||
ville høre hjemme, og hvad laboratoriets angrebsflade bliver, når den
|
||||
faktisk kaldes.
|
||||
4. Beregn `rip_off` i hånden ud fra `objdump -d foowosd`: find `buf`s
|
||||
`lea -0xNN(%rbp)` inde i `vulnerable_handler`, derefter `NN + 8`. foowosc
|
||||
gør præcis det; tjek dens regnestykke mod dit eget.
|
||||
5. `make hardened && make test-hardened`. Hvilken teknik falder for canaryen,
|
||||
og hvilken for NX? Hvorfor ændrer hærdning ikke, hvad `make status`
|
||||
rapporterer om *processen*?
|
||||
6. Sammenlign de to laboratoriers shellcodes: 23 bytes her, 32 for foosd. Hvad
|
||||
gør de ekstra 9 bytes, og hvorfor behøves de kun i SUID-tilfældet?
|
||||
7. Læs `become_shell()`s kommentar om den enkelte læse-cursor. Genskab
|
||||
fiaskotilstanden mentalt: to læsere på én socket betyder, at login-shellen
|
||||
æder ét byte per chunk — "uid=1000…" ankommer som "id=1000…". Hvorfor kan en
|
||||
relay-proces aldrig have denne fejl?
|
||||
|
||||
---
|
||||
|
||||
## Filer
|
||||
|
||||
```
|
||||
foowosd.c den sårbare root-daemon (hver linje kommenteret)
|
||||
foowosc.c exploitet (hver linje kommenteret)
|
||||
shellcode.S reference-assembly for 23-byte-payloaden
|
||||
tests/pty_wosuid_test.c pty-harnessen (markør + strenge id-form-tjek)
|
||||
Makefile build / run / run-root / run-root-ns / test /
|
||||
test-root / verify / hardened / clean …
|
||||
```
|
||||
|
||||
Søster-laboratorier: `../food.c`/`../fooc.c` (user-level-baseline, port 2342)
|
||||
og `../suid/` (SUID-root-daemon `foosd`/`foosc`, port 2343). Portene er bevidst
|
||||
forskellige — du kan køre alle tre på én gang og krydstjekke deres `ids=`-linjer
|
||||
i banneret.
|
||||
Loading…
Add table
Add a link
Reference in a new issue