PythonOnPills – Prosa 2013 writeup

Af Tits|GTFO

Dette program er et spinoff på The Matrix’s blue/red pill valg. Programmet er en python hjemmebagt webserver med noget client-side javascript og data gemt i en sqlite database.

I første omgang prøvede vi at se hvad applikationen kunne på port 2222, men den virkede ikke rigtigt, noget javascript ville ikke parse. Dette må have været en fejl fra arrangørens side.

Dernæst begyndte vi at kigge koden igennem. Vi fandt ud af at webserveren tager imod følgende requests:

  1. /take?name=<name>&pill=<0 eller 1>
    Tag en rød(0) eller blå(1) pille som personen <name>
  2. /distribution
    Giver antallet af personer der har taget henholdsvis rød og blå pille
  3. /me/<name>
    Fortæller om <name> har taget blå eller rød pille
  4. /
    Henter index.html
  5. /<andet>
    Henter <andet> filen (f.eks blue.png eller pills.js)

Flaget i denne kontekst er navnet på personen som vælger en pille.

Vi har fundet to fejl der kan udnyttes i denne applikation.

Request 3 - SQL injection

I url’en /me/<name> bliver <name> delen sendt direkte til sqlite, som ses i disse to kode snippets:

og

Så vi kan skrive præcis hvad vi har løst til i <name>.

Lad os benytte 2" AND 1=2 UNION SELECT group_concat(NAME, ":") FROM pills WHERE “1”=”1 som name. Dette vil give følgende SQL statement:
SELECT choice FROM pills WHERE name="2" AND 1=2 UNION SELECT group_concat(NAME, ":") FROM pills WHERE “1”=”1

Rød er her det originale SQL statement og blå er det indsatte. Dette SQL statement gør at den første del aldrig vælger noget (grundet 1=2 aldrig gælder) mens den anden del vil vælge alle navne og med kolon mellem dem. Implementering af exploitet kan se således ud (på én linje):

curl --max-time 1 -s $1':2222/me/2"%20AND%201=2%20UNION%20SELECT%20group_concat(NAME,%20":")%20FROM%20pills%20WHERE%20“1”=”1' | sed 's/:/\n/g'

Kald scriptet med en IP addresse, og denne vil blive angrebet.
--max-time 1 er benyttet for ikke at vente på hosts der ikke svarer
sed er benyttet til at udskifte kolon med linjeskift imellem navnene.

Fix SQLinjection

Nu har vi hugget en masse flag, hvordan skal vi så undgå at andre henter vores flag? Vi skal selvfølgelig benytte prepared statements.

Vi skal rette koden fra

til

Det samme kan gøres alle de stadig hvor SQL benyttes.

Request 5 - Path traversal

Hvis vi kigger på koden nedenfor skulle noget helst springe i øjnene:

Hvis / hentes, sender vi filen index.html i mappen www. For alle requests som ikke bliver behandlet specielt, kigger vi efter filen www/<path>, findes filen sender vi den.

Problemet er blot at der ikke bliver tjekket for om vi går ud af mappen www. F.eks hvis vi beder om ../pills.db får vi serveret databasefilen med alle flagene i - ups. Vi kan læse alle filer som webserveren kan tilgå. Vi hentede:

Dette gav os en hel masse flag, da dette var den første fejl vi opdagede under eventet.

Vores exploit så således ud:

Fix path traversal

Så hvordan retter vi denne fejl?

Vi ændrer koden fra

til

Altså: vi fjerner blot alle dobbelt punktummer.