Challenge Name

Problem

Exploit the function pointers in this program. It is also found in /problems/pointy_4_3b3533bd4e08119669feda53e8cb0502 on the shell server. Source.

Solution

  1. The provided program allows us to enter students and professors. Students can then rate the professors.

  2. The bug in the program is that we can select professors as students and students as professors. We can write the lastScore of a Professor and then treat it as a Student to control the scoreProfessor field.

  3. The Student and Professor structs are as follows:

     struct Professor {
         char name[NAME_SIZE];
         int lastScore;
     };
    
     struct Student {
         char name[NAME_SIZE];
         void (*scoreProfessor)(struct Professor*, int);
     };

    scoreProfessor is a function pointer that is in the same position relative to the struct as lastScore is in Professor. We can create a Professor and set the lastScore variable to the address of win(). Then, we can convert that professor to a student, which will override the scoreProfessor pointer and point it to the win() function. (scoreProfessor is pointed to giveScoreToProfessor() on line 79: student->scoreProfessor=&giveScoreToProfessor;.) Thus, when the scoreProfessor pointer is called (close to the end of the file: student->scoreProfessor(professor, value);), the win() function will be executed and we will get the flag.

  4. Script (script.py) Walkthrough:

    1. Allocate a student s1

    2. Allocate a professor p1

    3. Use student s1 to give the score

    4. Give the score to professor p1

    5. Set the lastScore attribute of professor p1 to the address of win()

    6. The loop in vuln.c restarts

    7. Allocate another student s2 (only necessary to proceed to next inputs in program)

    8. Allocate another professor p2 (only necessary to proceed to next inputs in program)

    9. Use professor p1 (which has the address of win()) to give a score. This converts professor p1 to a student, thus overwriting the scoreProfessor function pointer to win().

    10. Give the score to professor p1. This does not matter since we only care about the last line (student->scoreProfessor(professor, value);) where scoreProfessor (aka win()) is called. You could use p2 here as well since it is the extra professor we created earlier.

    11. Give a score of 0 to professor p1, but not really since the scoreProfessor function pointer points to win() and not giveScoreToProfessor() since we changed it by converting a Professor to a Student.

  5. Run the script.py python script.py USER=<username> PASSWORD=<password>:

     [*] '/home/<username>/Documents/PicoCTF/Binary Exploitation/pointy/vuln'
         Arch:     i386-32-little
         RELRO:    Partial RELRO
         Stack:    Canary found
         NX:       NX enabled
         PIE:      No PIE (0x8048000)
     [+] Connecting to 2019shell1.picoctf.com on port 22: Done
     [*] <username>@2019shell1.picoctf.com:
         Distro    Ubuntu 18.04
         OS:       linux
         Arch:     amd64
         Version:  4.15.0
         ASLR:     Enabled
     [+] Opening new channel: 'pwd': Done
     [+] Receiving all data: Done (14B)
     [*] Closed SSH channel with 2019shell1.picoctf.com
     [*] Working directory: '/tmp/tmp.klHpIRVO8i'
     [+] Opening new channel: 'ln -s /home/<username>/* .': Done
     [+] Receiving all data: Done (0B)
     [*] Closed SSH channel with 2019shell1.picoctf.com
     [*] win address: 0x8048696
     [+] Starting remote process b'/problems/pointy_4_3b3533bd4e08119669feda53e8cb0502/vuln' on 2019shell1.picoctf.com: pid 1203280
     [+] picoCTF{g1v1ng_d1R3Ct10n5_c7465fbf}

Flag

picoCTF{g1v1ng_d1R3Ct10n5_c7465fbf}

Last updated