Hoofdcategorieën
Topicacties

[Forumgame] Vind de kwetsbaarheid!

Pagina: 1 2 3 4 5 6 7 last

Reageer Nieuw Topic
BooBs for BraiNs
Berichten: 1.456
Reg. datum: 02 december 2002

quote:
PrisonerOfPain schreef op zaterdag 17 mei 2008 @ 10:26:
[...]


.data() geeft een string die niet null-terminated is terwijl strcmp dat wel verwacht, waar door 'ie over je boundries gaat. Zou verder niet weten hoe je er een exploit voor maakt.

PS. je hebt een virtual void ~CFixedSizeString dus 't compiled sowieso niet.
Je hebt een 2de bug gevonden, hoewel dit niet die is die ik zoek. Ik kon er even goed strncmp van maken met n=256.
Je bent echter wel op de goede weg.

Voorbeeldje heb ik niet door een compiler gehaald of getest, er kunnen dus idd foutjes zoals die destructor in staan, ik corrigeer het even.


Na even grondig denken over mijn voorbeeld heb ik een aanpassing moeten maken omdat ik even fout zat...

H!GHGuY wijzigde dit bericht 17-05-2008 11:37 (9%)

Yo momma's so fat, Dr. Martens had to kill 3 cows just to make her a pair of shoes.

nBrew
Berichten: 9.416
Reg. datum: 24 april 2000

quote:
Patriot schreef op vrijdag 16 mei 2008 @ 22:36:
[...]


Je levert zelf anders ook wel erg weinig context hoor. Je wil gewoon zeggen dat men dingen moet escapen, maar sommige dingen hoef je echt niet te escapen. Als je als developer de gebruikte variabele declareert is het niet nodig (mits er geen tekens in staan die de boel opfucken), en zéker geen exploit.

EDIT:

En wat SchizoDuckie bedoelt is dat je impliceert dat het één bepaald type is, terwijl het zomaar een ander type zou kunnen zijn (maar daar ben je zelf bij I guess).
Het gaat niet zozeer om het escapen dus want als je die waarde zelf samenstelt en je weet dat daar geen onveilige karakters inzitten is er geen probleem. Valt me tegen dat niemand het ziet eigenlijk. Als je een hash geeft aan een entry in een database dan moet je eerst checken of die hash er al niet is... De kans op collisions is niet heel groot maar zeker aanwezig. 2 entries met dezelfde hashes kan een hoop problemen opleveren (kijk bijv. naar youtube die de hash uit de url gebruikt als id).

Nog een keer de code:
PHP:

1
2
3
4
5
6
7
<?php
$strSql = '
    INSERT INTO
        video
    SET
        filename = "'
 . $strFilename . '",
        hash = "'
 . sha1(time()) . '"
    '
;
?>

En over het prefixen: bij ons op t werk is het een code standaard. Iedereen houdt zich daar keurig aan en dat is echt handig tijdens het doorkijken van een script.

Cartman! wijzigde dit bericht 17-05-2008 11:41 (6%)

 
3D Artist

quote:
Cartman! schreef op zaterdag 17 mei 2008 @ 11:41:
[...]
PHP:

1
2
3
4
5
6
7
<?php
$strSql = '
    INSERT INTO
        video
    SET
        filename = "'
 . $strFilename . '",
        hash = "'
 . sha1(time()) . '"
    '
;
?>

Zonder user input (hetzij via _POST, of via _GET) valt er natuurlijk weinig te exploiten... :) Maar misschien zie ik hier gewoon niet veel in, alleen een query is misschien iets te abstract.

Enige wat ik kan verzinnen is dat dit niet handig is en dat je misschien beter dit kan doen:
code:
1
sha1(time() .  $strFilename)

onnovanbraam.com | The Blueprints - Ref. Image Database
You're good, you're real good, but as long as I'm around, you'll always be second best

nBrew
Berichten: 9.416
Reg. datum: 24 april 2000

Het probleem is dat je dan nog steeds duplicates kunt krijgen in je database en dat wil je niet. Dus gewoon een functie maken die een hash genereert, checkt of ie niet voorkomt en als dat zo is recursief zichzelf aanroepen om een nieuwe te maken totdat je een unieke hebt. Je gaat toch ook geen nieuwsberichten hetzelfde id geven?
 
Jouw kleur (IP: R.G.B.void)

quote:
Cartman! schreef op zaterdag 17 mei 2008 @ 12:57:
Het probleem is dat je dan nog steeds duplicates kunt krijgen in je database en dat wil je niet. Dus gewoon een functie maken die een hash genereert, checkt of ie niet voorkomt en als dat zo is recursief zichzelf aanroepen om een nieuwe te maken totdat je een unieke hebt. Je gaat toch ook geen nieuwsberichten hetzelfde id geven?
Het probleem is dat met jouw voorbeeld niet direct duidelijk is waar de gemaakte hash voor dient. En het kan net zo goed zijn dat je daarnaast nog een kolom met auto_increment als primary key gebruikt.

Bezoek eens een willekeurige pagina
Of help mee met Tweak-City
Ik wili minder Kb's

nBrew
Berichten: 9.416
Reg. datum: 24 april 2000

Maar dan nog, bij Youtube zal iedere video vast een id hebben maar je krijgt deze gepresenteert adhv. de hash. Als een hash niet uniek hoeft te zijn dan heb je er niks aan in een database imo, tenzij deze als checksum dient.
 
:)

Als je unieke hashes wilt moet je natuurlijk met microtime of iets dergelijks gaan werken. De kans dat je twee gelijke hashes krijgt...

@hieronder: Wel volgens mijn C++ boek (C++ Grand Cru, Steve nogwat)

Sebazzz wijzigde dit bericht 17-05-2008 14:36 (20%)

programulator
Berichten: 21.395
Reg. datum: 26 september 2000

quote:
Sebazzz schreef op zaterdag 17 mei 2008 @ 09:59:
Je returned niet uit main() dus deze zal zowieso niet compilen.
main() behoeft geen return statement. Maar de return-type is wel altijd int.
quote:
@hieronder: Het is in ieder geval een goede gewoonte om het te doen
Waarom? main() is sowieso een special case (main() mag bijvoorbeeld ook niet aangeroepen worden door eigen code). 'return x' is in feite hetzelfde als 'exit(x)'. Waarom is dát dan geen goede gewoonte om neer te zetten? Als je een return-waarde onzinnig vind maak je 'm void, dat mag bij main() helaas niet. En in main() is geen return is hetzelfde als return 0 - iedere fatsoenlijke C++er weet dat :)

H!GHGuY: de bug is dat CFixedString::buffer nooit wordt afgesloten met een terminating 0. Je had gewoon strcpy() moeten gebruiken ipv strncpy(), wat mogelijk is omdat je de lengte daarvoor toch controleert.
BooBs for BraiNs
Berichten: 1.456
Reg. datum: 02 december 2002

quote:
.oisyn schreef op zaterdag 17 mei 2008 @ 14:05:
[...]

main() behoeft geen return statement. Maar de return-type is wel altijd int.


[...]

Waarom? main() is sowieso een special case (main() mag bijvoorbeeld ook niet aangeroepen worden door eigen code). 'return x' is in feite hetzelfde als 'exit(x)'. Waarom is dát dan geen goede gewoonte om neer te zetten? Als je een return-waarde onzinnig vind maak je 'm void, dat mag bij main() helaas niet. En in main() is geen return is hetzelfde als return 0 - iedere fatsoenlijke C++er weet dat :)

H!GHGuY: de bug is dat CFixedString::buffer nooit wordt afgesloten met een terminating 0. Je had gewoon strcpy() moeten gebruiken ipv strncpy(), wat mogelijk is omdat je de lengte daarvoor toch controleert.
er zit wel een terminating 0 in hoor ;) kijk nog maar eens goed...

Ik ben echter niet helemaal zeker dat het voorbeeld 100% klopt, maar mits minimale aanpassingen moet het toch zeker lukken...

Verklap'k em ?

H!GHGuY wijzigde dit bericht 17-05-2008 14:39 (7%)

Yo momma's so fat, Dr. Martens had to kill 3 cows just to make her a pair of shoes.

BooBs for BraiNs
Berichten: 1.456
Reg. datum: 02 december 2002

Ik kan er grandioos naast zitten, maar de redenering is zo:

je buffer moet je zo construeren:
code:
1
2
3
4
5
0:[256karakters zonder whitespace met minstens 1 \0 karakter - kan exploit code bevatten]
256:[vptr wijst naar 260]
260:[vptr0 wijst naar 268 of 0]
264:[vptr1 wijst naar 268 of 0]
268:[exploit code]

inlezen van een std::string kijkt naar EOF of whitespace. NUL-karakters worden afaik gewoon mee ingelezen.
strlen leest tot de eerste NUL-byte, str.data geeft alle data + bijhorende .size() (groter dan de strlen)
dus je kopieert over de vptr pointer. Doordat de initiele CFixedSizeString op de stack staat kun je de offsets daarvan gebruiken om tijdens de laatste inleesopdracht je code te injecteren met gekende offsets.

Door uiteindelijk de print() opdracht op te roepen jump je naar je exploit code.

Ik vermoed echter dat de set pointers naar CFixedSizeString zal moeten bevatten of anders wordt tijdens de copy-constructor actie de vptr van het geinserteerde object juist gezet.

Yo momma's so fat, Dr. Martens had to kill 3 cows just to make her a pair of shoes.

Fulltime #whatpulsert

quote:
Cartman! schreef op zaterdag 17 mei 2008 @ 13:35:
Maar dan nog, bij Youtube zal iedere video vast een id hebben maar je krijgt deze gepresenteert adhv. de hash. Als een hash niet uniek hoeft te zijn dan heb je er niks aan in een database imo, tenzij deze als checksum dient.
Dat zal allemaal gerust zo zijn hoor, maar niks van dit alles is uit de code te halen die jij geeft. Je geeft alleen de declaratie van een variabele, dat het een query betreft impliceert dan nog dat je het waarschijnlijk uit zou voeren maar dan houdt het toch echt wel op..

De fout is volgens jou dat er niet gekeken word of die hash al bestaat, maar uit je voorbeeld is onmogelijk te halen dat de hash uniek moet zijn. En dat een hash die niet uniek hoeft te zijn niet nuttig is, is ook niet waar. Je komt ze bijvoorbeeld vaak tegen in gebruikerssystemen. Een gebruiker die zijn wachtwoord is vergeten krijgt dan vaak een hash toegestuurd via de mail, waarna hij op een pagina alleen zijn wachtwoord kan veranderen als de hash klopt.

Je voorbeeld is leuk geprobeerd, maar helaas te abstract en ik kan me ook niet voorstellen dat het echt een exploit is.
No time for love, doctor Jones
Berichten: 5.481
Reg. datum: 20 september 2001

quote:
Cartman! schreef op zaterdag 17 mei 2008 @ 12:57:
Het probleem is dat je dan nog steeds duplicates kunt krijgen in je database en dat wil je niet. Dus gewoon een functie maken die een hash genereert, checkt of ie niet voorkomt en als dat zo is recursief zichzelf aanroepen om een nieuwe te maken totdat je een unieke hebt. Je gaat toch ook geen nieuwsberichten hetzelfde id geven?
Op die manier kan het nog steeds mis gaan. Twee users submitted verschillende files met toevallig dezelfde hash waarde. Eerste process queried de database of er duplicates zijn en vindt die niet. Op dat moment kicked het tweede process in, queried ook de database, en vindt ook geen duplicates. Vervolgens gaan ze allebei lekker insert queries draaien, en voila, een duplicate hash.

maw. je moet dan een atomic query maken die eerst select en dan conditioneel insert. Maar dan moet je nieuwe hashes kunnen genereren en loopen in je query: niet handig. Dus moet je je database locken gedurende de tijd dat je select/insert script draait. Dan kan je je site DoS-en door heel veel files te submitten ;)

concurrency exploits zijn natuurlijk ook leuk. Ik kan me wel iets indenken dat een Os een syncrhonized multiple producer/consumer buffer bijhoudt als event queue, maar dat op de simpelete manier met twee semaphores doet. Ik heb geen zin om een voorbeeld te geven, dat wordt te ingewikkeld. Het idee is in ieder geval dat je door een race-conditie naar hetzelfde slot kan schrijven als een ander process, en zo priviliged events zou kunnen faken ....

Zoijar wijzigde dit bericht 17-05-2008 15:48 (32%)

 
programulator
Berichten: 21.395
Reg. datum: 26 september 2000

quote:
H!GHGuY schreef op zaterdag 17 mei 2008 @ 14:37:
[...]


er zit wel een terminating 0 in hoor ;) kijk nog maar eens goed...
Nou wijs het maar aan dan, want ik zie het niet. strncpy() schrijft maximaal n characters. n is gelijk aan str.size(), dus strncpy() vult buffer met n characters zonder trailing 0.
quote:
H!GHGuY schreef op zaterdag 17 mei 2008 @ 14:54:
Ik kan er grandioos naast zitten
klopt ;)
quote:
strlen leest tot de eerste NUL-byte, str.data geeft alle data + bijhorende .size() (groter dan de strlen)
dus je kopieert over de vptr pointer.
Fout, om drie redenen. De vtable pointer staat meestal vooraan in de class, en dus niet achter buffer. Dit is wel zo praktisch omdat typeid() en dynamic_cast ook op void pointers moet kunnen werken. Als de vtable pointer achter buffer staat is het daadwerkelijke type zo goed als niet te achterhalen.

De andere reden is dat ook strncpy() niet altijd n characters kopiëert, maar maximaal n characters. Hij ie een 0 tegenkomt en i<n dan stopt dus gewoon. Je functie kopiëert daarom nooit meer dan 255 tekens door de if die ervoor staat. Als je altijd exact n characters wilt kopiëren moet je memcpy() gebruiken. En sowieso zelf de trailing 0 erachter zetten, want ook strncpy() doet dat niet als er al n characters geschreven zijn.

De derde noemde je zelf al:
quote:
Ik vermoed echter dat de set pointers naar CFixedSizeString zal moeten bevatten of anders wordt tijdens de copy-constructor actie de vptr van het geinserteerde object juist gezet.
Klopt als een bus ;)

.oisyn wijzigde dit bericht 17-05-2008 22:11 (8%)

Berichten: 162
Reg. datum: 29 maart 2004

Ach Zojar, jammer dat je nog niet gehoord hebt van Database Transactions. Dat maakt je hypothetisch voorbeeld onmogelijk.
 
Berichten: 18
Reg. datum: 02 februari 2001

quote:
H!GHGuY schreef op zaterdag 17 mei 2008 @ 09:54:
C++:
1
2
3
4
5
6
7
8
9
class CFixedSizeString
{
  public:
     CFixedSizeString(const std::stringstr)
     {
        if (strlen(str.c_str()) > 255)
           throw "badly sized string";
        strncpy(bufferstr.data(), str.size());
     }

Normaal gebruik ik geen std::string, maar is deze aanname wel juist: strlen(str.c_str())==str.size(). Als de string meerdere '\0' characters heeft, kan dat evt mis gaan...
 
programulator
Berichten: 21.395
Reg. datum: 26 september 2000

En als je even door had gelezen dan was je erachter gekomen dat dat idd de clue was ;)
No time for love, doctor Jones
Berichten: 5.481
Reg. datum: 20 september 2001

quote:
fl!pulI schreef op zaterdag 17 mei 2008 @ 21:35:
Ach Zojar, jammer dat je nog niet gehoord hebt van Database Transactions. Dat maakt je hypothetisch voorbeeld onmogelijk.
Het zal je verbazen waar ik allemaal van gehoord heb ;) Zoals ik al zei, dan moet je een atomic query gebruiken, en dat kan idd middels een transaction. Maar aangezien het hier om kwetsbaarheden ging, merk ik op dat dit niet doen ook vaak een kwestbaarheid kan opleveren. Ik heb genoeg code gezien in het verleden die op deze manier records insert: select max(id) from users, fetch record set $result, insert user met id=$result. (in mijn tijd was MySQL overigens de meest gebruikte database icm web-development, en in de oude versies had je helaas niet de luxe van transaction support)

Zoijar wijzigde dit bericht 18-05-2008 11:52 (9%)

 
BooBs for BraiNs
Berichten: 1.456
Reg. datum: 02 december 2002

quote:
.oisyn schreef op zaterdag 17 mei 2008 @ 19:12:
[...]

Nou wijs het maar aan dan, want ik zie het niet. strncpy() schrijft maximaal n characters. n is gelijk aan str.size(), dus strncpy() vult buffer met n characters zonder trailing 0.


[...]

klopt ;)

[...]

Fout, om drie redenen. De vtable pointer staat meestal vooraan in de class, en dus niet achter buffer. Dit is wel zo praktisch omdat typeid() en dynamic_cast ook op void pointers moet kunnen werken. Als de vtable pointer achter buffer staat is het daadwerkelijke type zo goed als niet te achterhalen.

De andere reden is dat ook strncpy() niet altijd n characters kopiëert, maar maximaal n characters. Hij ie een 0 tegenkomt en i<n dan stopt dus gewoon. Je functie kopiëert daarom nooit meer dan 255 tekens door de if die ervoor staat. Als je altijd exact n characters wilt kopiëren moet je memcpy() gebruiken. En sowieso zelf de trailing 0 erachter zetten, want ook strncpy() doet dat niet als er al n characters geschreven zijn.

De derde noemde je zelf al:

[...]

Klopt als een bus ;)
niet schieten is altijd mis ;)

Leer ik zelf ook gelijk wat bij...

Yo momma's so fat, Dr. Martens had to kill 3 cows just to make her a pair of shoes.

Jouw kleur (IP: R.G.B.void)

Volgens mij zijn we nu door de puzzels heen. Wie plaatst de volgende?

Bezoek eens een willekeurige pagina
Of help mee met Tweak-City
Ik wili minder Kb's

programulator
Berichten: 21.395
Reg. datum: 26 september 2000

Tja, na de simpele buffer overruns en triviale XSS voorbeelden hebben we het wel zo'n beetje gehad. Ik kan me nog iets voorstellen met een UBB-achtige parser waarin je URLs of IMGs kunt stoppen waarbij je ook op moet passen dat daarin geen javascript oid is uit te voeren, maar dan wordt het voorbeeld al snel te complex om hier te posten.
Berichten: 3.652
Reg. datum: 20 maart 2001

Ach, klassieker die ik bijna wekelijks voorbij zie komen :
code:
1
2
3
$res = mysql_query('SELECT username FROM users WHERE name="pietje";'); 
$row = mysql_fetch_assoc($result);
$query2= mysql_query('update rechten set (adminright=True) where username="' . $row['username'] . '"');

Gomez12 wijzigde dit bericht 20-05-2008 20:34 (3%)

 
Meerkats

Dankzij het verschil tussen $res en $result gaat daar niets fout, behalve dan dat je een whopping notice krijgt. :P

Talkin.nl daily photoblog
Day 1022: Meerkats
Foto specs: Canon 300D, Sigma 70-200 f/2.8 HSM, 1/500s, f/5.0, ISO 400

nBrew
Berichten: 9.416
Reg. datum: 24 april 2000

Het is sowieso niet handig om in de rechtentabel de naam te gebruiken ipv. het userid, is dat wat je bedoeld? Moeten er trouwens geen quotes om True heen? En de haakjes zijn ook overbodig.

offtopic: het adminright=true is ook erg beperkend voor een applicatie... ;)
 
Volgens mij zit er geen fout in? Je kan je registreren als piet" OR 1=1 maar ik denk dat niet eens gaat werken (zowiezo niet als je pietje hard erin bakt).
quote:
Cartman! schreef op dinsdag 20 mei 2008 @ 21:10:
Het is sowieso niet handig om in de rechtentabel de naam te gebruiken ipv. het userid, is dat wat je bedoeld? Moeten er trouwens geen quotes om True heen? En de haakjes zijn ook overbodig.

offtopic: het adminright=true is ook erg beperkend voor een applicatie... ;)
Dan wordt het meer een "Debug mijn script" topic...

Megamind wijzigde dit bericht 20-05-2008 21:12 (58%)

 
Geen idee...
Berichten: 2.751
Reg. datum: 25 juni 2005

Wat gebeurt er als $row leeg is?

Tweak-city
Spel- of grammaticafout gevonden? Geef het even door via DM (en ook waarom het fout is).

Pagina: 1 2 3 4 5 6 7 last



VNU Media logo Powered by True

© 1998 - 2008 Tweakers.net - Alle rechten voorbehouden

Uitgever van: