Initial commit
This commit is contained in:
commit
394e3be54d
41 changed files with 16315 additions and 0 deletions
398
suid/README.NL.md
Normal file
398
suid/README.NL.md
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
# SUID-root-RCE-lab — `foosd` (daemon) + `foosc` (exploit)
|
||||
|
||||
Een begeleider van het hoofdlaboratorium (`food` / `fooc`, een gewone daemon
|
||||
waar een bufferoverloop je een *gebruiker*-shell geeft). Dit voegt de
|
||||
gevaarlijkste wijziging van één teken in Unix toe: **de setuid-bit**.
|
||||
|
||||
> `chmod u+s` verandert "de aanvaller kan code draaien op deze host" in "de
|
||||
> aanvaller kan code draaien als **root** op deze host".
|
||||
|
||||
Die zin is het hele lab. Alles hieronder is het mechanisme eronder,
|
||||
opgeschreven, zodat je wanneer je je eigen software schrijft precies weet welke
|
||||
twee of drie bestandssysteem-attributen en compilerflags bepalen of een
|
||||
geheugenveiligheidsbug in jouw code een ergernis of een root-shell is.
|
||||
|
||||
De uiteindelijke demo, wanneer `foosd` setuid-root is, is een **root-shell**
|
||||
die over het netwerk wordt geopend door 32 bytes handgeschreven shellcode uit
|
||||
te voeren.
|
||||
|
||||
---
|
||||
|
||||
## 1. Wat de setuid-bit daadwerkelijk doet
|
||||
|
||||
Elk proces op Linux draagt drie user-ID's, en de setuid-bit rommelt aan de
|
||||
verhouding ertussen:
|
||||
|
||||
| ID | Naam | Betekenis |
|
||||
|----|------|---------|
|
||||
| `ruid` | reële user-ID | de account die het proces *startte* |
|
||||
| `euid` | effectieve user-ID | wat de kernel controleert wanneer hij toegang handhaaft |
|
||||
| (saved) | opgeslagen set-user-ID | een "spoor" waarnaar een bevoorrecht proces later kan terugkeren |
|
||||
|
||||
Een normaal programma heeft `ruid == euid`. Wanneer je een binair bestand
|
||||
uitvoert met de setuid-bit gezet, eigendom van root:
|
||||
|
||||
```text
|
||||
ruid = jij (bijv. 1000, "hanez")
|
||||
euid = de eigenaar (bijv. 0, "root")
|
||||
```
|
||||
|
||||
Het proces heeft dus **roots autoriteit**, ook al is de gebruiker die het
|
||||
startte volkomen gewoon. Elke controle die de kernel uitvoert — kan dit proces
|
||||
`/etc/shadow` lezen? een bestand schrijven? een ander proces doden? — wordt
|
||||
beantwoord met `euid`, dus "ja, het is root".
|
||||
|
||||
`foosd` is een netwerkdaemon. Hij bindt een poort en `fork()`t daarna een kind
|
||||
per verbinding. Een fork *erft* de euid, dus elk kind dat een verbinding
|
||||
afhandelt, is ook root. De overloop in `foosd`s `vulnerable_handler()` is
|
||||
daarom een overloop *binnenin een root-proces*.
|
||||
|
||||
**Diagnosticeer het zelf wanneer de daemon draait:**
|
||||
|
||||
```console
|
||||
$ ./foosd ... # zie de logregel die hij bij de start print
|
||||
[foosd 1234] startup: ruid=1000 euid=0 -> ROOT process
|
||||
```
|
||||
|
||||
en vanuit het exploit:
|
||||
|
||||
```console
|
||||
$ ./foosc -t leak
|
||||
foosc: target euid=0 ruid=1000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Het lab in één oogopslag
|
||||
|
||||
| Bestand | Rol |
|
||||
|------|------|
|
||||
| `foosd.c` | De bewust kwetsbare daemon (eigenaar van de bugs). Draai als *setuid-root*-binary voor de root-shell-demo. |
|
||||
| `foosc.c` | Het exploit. Gebruikt standaard de 32-byte `setreuid + execve`-shellcodetechniek. |
|
||||
| `shellcode.S` | De referentie-shellcode; `make verify` diff't het tegen de byte-array in `foosc.c`. |
|
||||
| `tests/pty_suid_test.c` | Test-harness. Drijft `foosc` door een pseudo-terminal en bewijst zowel "er draaide een shell" *als* "die was root" (`uid=0(`). |
|
||||
| `Makefile` | Build, `setuid`/`unsetuid`-helpers, testmatrix. |
|
||||
| `README.md` | Dit bestand. |
|
||||
|
||||
> **Waarom een pty?** De laatste actie van het exploit is je terminal
|
||||
> doorschakelen naar de shell die op het slachtoffer draait. Een pipe of
|
||||
> here-doc komt aan de verkeerde kant van die doorschakeling terecht; een echte
|
||||
> terminal is vereist.
|
||||
|
||||
---
|
||||
|
||||
## 3. Snelle start
|
||||
|
||||
```console
|
||||
$ make # bouw alles, als je normale gebruiker
|
||||
$ make setuid # één keer, vraagt om sudo: chown root + chmod u+s
|
||||
$ make run # start foosd op 127.0.0.1:2343
|
||||
$ make test-suid # volledige matrix; shellcode + ret2win-root moeten root geven
|
||||
```
|
||||
|
||||
Interactieve rooktest:
|
||||
|
||||
```console
|
||||
$ ./foosc -t shellcode
|
||||
...
|
||||
foosc: target euid=0 ruid=1000
|
||||
foosc: shell is on the victim (root if foosd is SUID); relaying
|
||||
# id
|
||||
uid=0(root) gid=0(root) groups=0(root) <-- je bent root, op het slachtoffer
|
||||
# exit
|
||||
```
|
||||
|
||||
Wanneer je klaar bent:
|
||||
|
||||
```console
|
||||
$ make stop
|
||||
$ make unsetuid # hygiëne: laat nooit een root-SUID-binary achter
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. *Wanneer moet ik de SUID-bit zetten?* — het antwoord dat je vroeg
|
||||
|
||||
Precies **één keer, na het bouwen, vóór je de daemon start voor de
|
||||
root-shell-demo's** — en alleen op een machine die van jou is, geschikt om weg
|
||||
te gooien en losgekoppeld van het netwerk:
|
||||
|
||||
```console
|
||||
$ make # compileer foosd, foosc, tests
|
||||
$ make setuid # <-- HET MOMENT. sudo chown root:root foosd && sudo chmod u+s foosd
|
||||
$ make run # start NÁ het zetten van de bit
|
||||
```
|
||||
|
||||
Twee regels die belangrijker zijn dan het precieze tijdstip:
|
||||
|
||||
1. **Zet hem alleen als de binary klaar is.** Als je herbouwt (`make` /
|
||||
`make clean`) nadat je de bit hebt gezet, krijg je een "Permission denied"
|
||||
bij het schrijven van root-bezeten outputbestanden — en als je de herbouw
|
||||
forceert, herschept de toolchain het bestand **zonder** de `s` en maak je de
|
||||
opzet stilletjes ongedaan. De canonieke volgorde bij elke herbouw is daarom
|
||||
|
||||
```console
|
||||
$ make unsetuid && make && make setuid
|
||||
```
|
||||
|
||||
2. **Haal hem weg als je klaar bent.** `make unsetuid`. Een levende,
|
||||
root-bezeten setuid-binary met een exploiteerbare bug in je boom is geen
|
||||
leermiddel, het is een root-gat met een compilerfout tussen zichzelf en
|
||||
niets. Op een gedeelde of productiemachine: **doe niets van dit alles.** De
|
||||
daemon weigert bovendien standaard iets anders dan loopback te binden (zie
|
||||
§7).
|
||||
|
||||
Als je het exploit *zonder* ooit de bit te zetten draait, gaat er niets
|
||||
kapot — de payload landt nog steeds, en je krijgt nog steeds een shell. Het
|
||||
verschil zit in één getal, en het exploit zegt het hardop:
|
||||
|
||||
```console
|
||||
foosc: WARNING: the daemon is NOT running with euid 0.
|
||||
The payload will still land, but the shell will be
|
||||
a plain user shell, not root.
|
||||
Fix: sudo make setuid
|
||||
```
|
||||
|
||||
Het "werkte, maar niet root"-resultaat is zelf onderdeel van het lab. Onthoud
|
||||
dat voor de volgende sectie.
|
||||
|
||||
---
|
||||
|
||||
## 5. Het mechanisme — en de twist die SUID interessant maakt
|
||||
|
||||
### 5.1 De overloop (identiek aan `food`)
|
||||
|
||||
De handler van `foosd` geeft een `read()` 512 bytes vertrouwen terwijl hij er
|
||||
een 64-byte stack-buffer aan reikt:
|
||||
|
||||
```c
|
||||
char buf[64];
|
||||
n = read(fd, buf, 512); /* <- CWE-120: 448 bytes over de rand */
|
||||
```
|
||||
|
||||
Op x86-64 groeit de stack naar beneden. Het exploit schrijft 64 bytes rommel
|
||||
om `buf` te vullen, 8 om de opgeslagen framepointer te vullen en nog 8 om de
|
||||
**opgeslagen retouradres** te vervangen. Wanneer `vulnerable_handler` de `ret`
|
||||
uitvoert, poppt de CPU de waarde van de aanvaller in `RIP` —
|
||||
aanvaller-gecontroleerde code-uitvoering. Het exploit vindt de exacte afstand
|
||||
(88 bytes voor deze build) door `objdump`-output te parsen in plaats van die te
|
||||
hardcoden, zodat het getal herbouwen overleeft.
|
||||
|
||||
### 5.2 De twist: de shell weigert root te zijn
|
||||
|
||||
Hier is waar "SUID-bug → spawn /bin/sh → root" fout zou gaan, en waarom dit lab
|
||||
precies de vorm heeft die het heeft.
|
||||
|
||||
Wanneer een setuid-root-programma draait, is zijn `ruid` nog steeds de
|
||||
startende gebruiker en is zijn `euid` root. Als het programma — of de aanvaller
|
||||
— nu een shell start:
|
||||
|
||||
* `execve("/bin/sh")` verandert de uids **niet**; het nieuwe proces erft
|
||||
`(ruid=1000, euid=0)`.
|
||||
* bash (en dash) **controleert die exacte toestand bij de start**. Uit de
|
||||
bash-handleiding: *"If the shell is started with the effective user (group)
|
||||
id not equal to the real user (group) id, and the -p option is not supplied,
|
||||
… the effective user id is set to the real user id."*
|
||||
|
||||
Dus de shell kijkt naar zichzelf en *laat root vallen* — een verdediging die de
|
||||
shell-auteurs precies tegen dit aanval bouwden (de historische reden was het
|
||||
setuid-shell-/setuid-scriptprobleem). Het resultaat is de "werkte, maar niet
|
||||
root"-gevallen:
|
||||
|
||||
| Techniek | Wat hij uitvoert | Resulterende uid |
|
||||
|-----------|------------------|---------------|
|
||||
| `ret2win` | `foosd`s `win()` → `execl("/bin/sh")` | **1000** — shell landde, root gereset door bash |
|
||||
| `ret2libc` | `system("/bin/sh")` → verse `sh -c '/bin/sh'` | **1000** — dezelfde reset, één niveau lager |
|
||||
| `ret2win-root` | `foosd`s `win_root()` → `setreuid(0,0); execl("/bin/sh")` | **0** — ruid opgeruimd vanuit C |
|
||||
| `shellcode` | 32 bytes: `setreuid(0,0); execve("/bin/sh")` | **0** — ruid opgeruimd vanuit machinecode |
|
||||
|
||||
Degene die root bereiken, verschillen van degene die dat niet doen in precies
|
||||
één idee: **ze ruimen de *reële* uid op, niet alleen de effectieve.**
|
||||
|
||||
```c
|
||||
setuid(0) /* zet euid op 0, maar ruid blijft 1000:
|
||||
bash ziet nog steeds euid != ruid en reset NOG STEEDS. */
|
||||
setreuid(0, 0) /* zet BEIDE: ruid = euid = 0.
|
||||
bash ziet gelijke uids en houdt root. */
|
||||
```
|
||||
|
||||
Daarom begint de klassieke `/bin/sh`-shellcode die je overal op internet vindt
|
||||
met een uid-opruimend syscall — en daarom is de shellcode hier 32 bytes in
|
||||
plaats van 23: de eerste vijf instructies zijn
|
||||
|
||||
```asm
|
||||
xor edi, edi ; ruid = 0
|
||||
xor esi, esi ; euid = 0
|
||||
push 0x71 ; 113 = __NR_setreuid
|
||||
pop rax
|
||||
syscall
|
||||
```
|
||||
|
||||
### 5.3 Dus wat is het exploit, van begin tot eind?
|
||||
|
||||
1. `foosc` leest het banner van `foosd` over de socket. Het krijgt:
|
||||
- `ids=0/1000` — euid/ruid (de SUID-zelfdiagnose)
|
||||
- `stack=…` en `libc=…` — pointers (de ASLR-leaks)
|
||||
- `BUF=…` — het exacte adres van de buffer die het op het punt staat te
|
||||
laten overlopen
|
||||
2. Uit de doel-binary (via `objdump`) leert het `rip_off` en de adressen van
|
||||
`win()` / `win_root()`.
|
||||
3. Uit *zijn eigen* libc (via `/proc/self/maps` + `dlsym` + een geheugenscan)
|
||||
meet het de offsets van `system`, `read`, `/bin/sh` en een
|
||||
`pop rdi; ret`-gadget — niets is hardcoded.
|
||||
4. Het stelt de payload samen. Voor `-t shellcode` is dat:
|
||||
`[32-byte-setreuid+execve-code][padding tot RIP][ret-fix][adres van buf]`.
|
||||
5. `foosd`s `read()` loopt over; de `ret` landt op de shellcode; de kernel
|
||||
voert `setreuid(0,0)` uit (geen probleem: euid 0 is bevoorrecht) en daarna
|
||||
`execve` van `/bin/sh`. bash start met `ruid == euid == 0` en blijft root.
|
||||
6. `foosc` schakelt je terminal door naar die root-shell, tot je `exit` typt.
|
||||
|
||||
Eén gemakdetail dat mensen veel tijd kost als het wordt gemist: het exploit
|
||||
test elk uid-opruimgedrag **zonder** eerst de setuid-bit nodig te hebben. Draai
|
||||
`make test` vóór `make setuid`, en je ziet elke techniek een shell landen terwijl
|
||||
`ROOT=MISSING` staat; draai `make test-suid` ná `make setuid`, en `ROOT=SEEN`
|
||||
verschijnt bij de twee technieken die de reële uid opruimen. Die A/B is de hele
|
||||
les, in tien seconden uitgevoerd.
|
||||
|
||||
---
|
||||
|
||||
## 6. De oude one-liners — en waarom de meeste dood zijn
|
||||
|
||||
Heb je over SUID gelezen, dan heb je over `PATH`-kapingen, `LD_PRELOAD` en
|
||||
setuid-shells gelezen. Alle drie zijn klassiek, en alle drie falen op een
|
||||
modern systeem tegen *dit programma*. Het is de moeite waard om precies te
|
||||
weten waarom, want de redenen zijn de verdedigingen die je gratis krijgt:
|
||||
|
||||
| Aanvalsklasse | Oude bewering | Waarom hij faalt op een moderne machine |
|
||||
|--------------|-----------|------------------------------|
|
||||
| `LD_PRELOAD` van een kwaadaardige bibliotheek | "Het setuid-programma laadt mijn `.so` en draait mijn code als root." | De kernel markeert een setuid-binary als **AT_SECURE**; glibc negeert daarna `LD_PRELOAD`, `LD_LIBRARY_PATH`, `LD_DEBUG` en vrienden. De omgeving wordt behandeld als *onbetrouwbare input*. `LD_PRELOAD` tegen een setuid-binary is een no-op. |
|
||||
| `PATH`-kaping (`system("ls")` met een vergiftigde PATH) | "Wijs PATH naar een map met mijn neppe `ls`; het root-programma draait hem." | Een ander gezicht van hetzelfde verdedigingen: een AT_SECURE-proces krijgt een **gesaneerde `PATH`** (een veilige standaard, grofweg `/usr/local/bin:/usr/bin:/bin`) voor `system()`/`execvp`, dus de vergiftigde map wordt nooit geraadpleegd. |
|
||||
| Setuid-`system()`-commando-injectie | "Het geïnjecteerde commando draait met euid 0." | `system()` draait het commando in een verse `/bin/sh`, en die shell — §5.2 — reset `euid = ruid` bij de start. Het geïnjecteerde commando wordt uitgevoerd met de *reële* uid. (Het blijft een bug; het escaleert alleen niet meer via `/bin/sh`.) |
|
||||
| Setuid-root-shell op de schijf (`cp /bin/sh /tmp; chmod u+s`) | "Draai hem, krijg root." | Precies wat hierboven verdedigd wordt, en dat is waarom moderne distro's geen enkele setuid-root-shell leveren. Zelfs als je er één kunt maken, weigert bash euid 0 te houden tenzij hij met `-p` wordt gestart. |
|
||||
|
||||
Wat blijft leven, en dat is dit lab: **het programma is *al* root wanneer het
|
||||
draait.** Je hebt de omgeving of `system()` niet nodig; je hebt nodig dat het
|
||||
programma *jouw* code uitvoert (via een geheugenbeschadigingsbug) terwijl het
|
||||
bevoorrecht is, en dat jouw code zorgvuldig genoeg is om zelf de uid-mismatch
|
||||
recht te zetten — `setreuid(0,0)` — voordat het je een shell overhandigt.
|
||||
Geheugenbeschadiging + SUID is de combinatie die nog steeds in `uid=0` eindigt,
|
||||
en dat is precies waarom geheugenveilige talen, canaries en no-execute-stacks
|
||||
geen modebeslissing zijn.
|
||||
|
||||
---
|
||||
|
||||
## 7. De veiligheidsheurlingen die in de daemon zijn ingebouwd
|
||||
|
||||
`foosd` is bewust het *slechtste* stuk software in dit repository, dus het
|
||||
draagt ook de meeste leuningen:
|
||||
|
||||
1. **Alleen loopback, afgedwongen.** `foosd` weigert elke bind-adres buiten
|
||||
loopback, tenzij je `-L` geeft. Een setuid-root-listener op een echte
|
||||
interface is een externe root-dienst; de weigering is de standaard, zodat de
|
||||
gevaarlijke toestand bewust moet worden ingetypt.
|
||||
2. **Zelfdiagnose.** Bij de start logt hij `ruid`/`euid` en of hij als root
|
||||
draait, zodat de console de toestand toont waarvan het exploit afhangt.
|
||||
3. **De log bereikt de client nooit.** De daemon reserveert een privé
|
||||
log-descriptor vóór sockets fd 1 vervangen, zodat crash-reporter-output en
|
||||
interne paden niet door de aanvaller over de draad teruggelezen kunnen
|
||||
worden.
|
||||
4. **Crash-reporter.** Een SIGSEGV-handler logt `RIP`/`RSP` — de waarde die de
|
||||
aanvaller in het retouradres schreef — zodat een succesvolle overname
|
||||
zichtbaar is in `foosd.log` in plaats van een stille dood.
|
||||
5. **`make unsetuid`.** Het verwijderen van de bit is gescript, omdat hem laten
|
||||
staan de faaltoestand is die mensen daadwerkelijk hebben.
|
||||
|
||||
---
|
||||
|
||||
## 8. Tegenmaatregelen — wat elke stopt en wat hij *niet* stopt
|
||||
|
||||
Toegepast op `foosd` via `make hardened`, één voor één of samen:
|
||||
|
||||
| Tegenmaatregel | Wat hij stopt | Wat hij *niet* stopt |
|
||||
|------------|---------------|-------------------------|
|
||||
| `-fstack-protector-strong` (canary) | De overloop: `ret` detecteert een beschadigde canary en aborted vóór het adres van de aanvaller wordt gebruikt. Stopt hier **alle vier** de technieken — ze delen het ene kwetsbare `read()`. | Niets aan *het ontwerp*: de binary is nog steeds setuid-root; een andere bug (format-string-`%n`, heap-overflow, use-after-free) heeft geen canary om af te laten gaan. |
|
||||
| `-fPIE -pie` (ASLR voor de binary) | Gebruik van voorspelbare `win()`/`win_root()`-adressen (de ret2win-technieken). | De shellcode-techniek, als er nog een stack-adres lekt (`BUF=`-regel). |
|
||||
| `-z noexecstack` (NX / W^X) | De shellcode: de CPU weigert instructies op te halen van een data-only-pagina, dus een sprong naar `buf` is een SIGSEGV. | ROP — code draaien die al bestaat (`ret2libc`). |
|
||||
| Alle drie samen | Een moeilijk-te-laten-overlopen, gerandomiseerde binary met een niet-uitvoerbare stack. Zo ziet een normale geharde build eruit. | De setuid-bit. **Een geharde SUID-binary is nog steeds een SUID-binary.** Overleeft er een bereikbare geheugenveiligheidsbug, dan is het nog steeds "bug in een root-proces". |
|
||||
|
||||
Het consolebewijs is `make test-hardened`, dat de geharde build inwisselt en
|
||||
laat zien hoe alle technieken bij de canary sterven, terwijl
|
||||
`foosd_hardened.log` `*** stack smashing detected ***` opvangt.
|
||||
|
||||
Twee tegenmaatregelen op ontwerpniveau die geen enkele compilerflag levert, en
|
||||
die het hoofdlaboratorium (`food`) ook gebruikt:
|
||||
|
||||
- **Minste privilege.** Een daemon voor een onbevoordeelde poort (2343 > 1024)
|
||||
heeft geen legitieme behoefte aan root. Een correcte `foosd` zou binden en
|
||||
daarna `setgroups`/`setgid`/`setuid` naar een onbevoorrechte account en
|
||||
*bevestigen dat het hield* (de correcte versie staat in de bron als
|
||||
`drop_privs()`, nooit aangeroepen — het niet-aanroepen is bug nr. 3 van het
|
||||
lab).
|
||||
- **Beperk de read.** `n = read(fd, buf, sizeof(buf) - 1)`. Eén correcte regel
|
||||
overtreft elke compilerflag in de tabel.
|
||||
|
||||
---
|
||||
|
||||
## 9. Het wire-protocol (zodat je de daemon met netcat kunt lezen)
|
||||
|
||||
```text
|
||||
FOOSD 1.0 - deliberately vulnerable SUID service
|
||||
Type 'quit' to disconnect. Buffer = 64 bytes, read accepts 512.
|
||||
FOOSD 1.0 ids=0/1000 leak stack=0x7ffd... libc=0x7f...
|
||||
BUF=0x7ffd...
|
||||
```
|
||||
|
||||
* `ids=euid/ruid` — kon niet als `euid=`/`ruid=` geprint worden, omdat de
|
||||
test-harness een shell bewijst door op het letterlijke `uid=` te greppen, en
|
||||
het banner mag dat niet bevatten (een sonde die de handtekening met het
|
||||
antwoord deelt, is een klassieke fout-positief- val; zie de commentaar in
|
||||
`foosd.c`). De harness vereist bovendien de strikte `id`-outputvorm —
|
||||
`uid=NNN(...)` — zodat niets wat de daemon of het exploit print het aan
|
||||
toeval kan laten voldoen: `foosc`s eigen "target euid=… ruid=…" bevat `uid=`
|
||||
als deelstring, wat ooit een geharde test een shell liet melden die nooit had
|
||||
gedraaid.
|
||||
* `stack=`, `libc=`, `BUF=` — de ASLR-leaks: laten shellcode en ret2libc exacte
|
||||
adressen berekenen.
|
||||
|
||||
---
|
||||
|
||||
## 10. Oefeningen
|
||||
|
||||
1. **Beschouw de niet-root-degradatie.** Draai `make test` *vóór* `make
|
||||
setuid`, en daarna nog eens achteraf. Verklaar de `ROOT=SEEN`-verandering
|
||||
met het ruid/euid-verhaal in §5.2.
|
||||
2. **Lees de crash.** Draai `./foosc -t demo -n` en lees daarna `foosd.log`.
|
||||
De regel `RIP=0x4141414141414141` is de padding van de aanvaller — het bewijs
|
||||
dat de overloop, niet toeval, de uitvoering bestuurt.
|
||||
3. **Voeg de canary toe.** `make hardened` en verander zelf de
|
||||
`test-hardened`-lus; de logregel `*** stack smashing detected ***` is de
|
||||
verdediging die werkt.
|
||||
4. **Schakel het lek uit.** Commentaar de `BUF=`-regel in `foosd.c` uit, bouw
|
||||
opnieuw, en zie `-t shellcode` van deterministisch naar een raadspel
|
||||
veranderen. Die ene regel is de reden dat echte ASLR-bypasses een heel veld
|
||||
zijn.
|
||||
5. **Het `-p`-experiment.** Verander in een kopie van `win()`
|
||||
`execl("/bin/sh", "sh", NULL)` naar `execl("/bin/sh", "sh", "-p", NULL)` en
|
||||
observeer root. `-p` is de gedocumenteerde nooduitgang uit de wacht van de
|
||||
shell — en de reden dat het advies "spawn gewoon een shell" uit oude
|
||||
write-ups onvolledig is.
|
||||
6. **Waarom niet `setuid(0)`?** Herschrijf de shellcode om `setuid(0)` te
|
||||
roepen in plaats van `setreuid(0,0)` (syscall 105). De shell landt nog
|
||||
steeds — en zakt nog steeds naar `uid=1000`. Dat is het meest leerzame
|
||||
één-regel-experiment van het hele repository.
|
||||
|
||||
---
|
||||
|
||||
## 11. Veiligheid en opruimen
|
||||
|
||||
- Alleen loopback, als standaard en volgens ontwerp; `-L` bindt verder, en
|
||||
alleen een weg-te-gooien-VM zou het überhaupt moeten overwegen.
|
||||
- Dit is een root-shell-lab. Draai het niet op een machine die ertoe doet, en
|
||||
richt `foosc -h` niet op iets dat je niet bezit.
|
||||
- Opruimritueel: `make stop` en daarna `make unsetuid`, en als je de boom weer
|
||||
vlekkeloos wilt: `sudo make clean`.
|
||||
|
||||
```console
|
||||
$ make stop
|
||||
$ make unsetuid
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue