Skip to content

Instantly share code, notes, and snippets.

@Aplet123
Created April 15, 2020 11:43
Show Gist options
  • Save Aplet123/1fc31d30062ea7588d3e6f193ffb6443 to your computer and use it in GitHub Desktop.
Save Aplet123/1fc31d30062ea7588d3e6f193ffb6443 to your computer and use it in GitHub Desktop.
IJCTF PreCTF Rev Writeups

Rev0

What does func("b4by_r3vers1ng_ch4ll") return?

func:
        push      rbp
        mov       rbp, rsp
        sub       rsp, 16
        mov       QWORD PTR [-16+rbp], rdi
        mov       rax, 0x0cafebabe
        mov       QWORD PTR [-8+rbp], rax
..B1.2:
        mov       rax, QWORD PTR [-16+rbp]
        movsx     eax, BYTE PTR [rax]
        movsx     rax, al
        test      eax, eax
        je        ..B1.4
        mov       rax, 0x0deadc0de
        imul      rax, QWORD PTR [-8+rbp]
        mov       QWORD PTR [-8+rbp], rax
        mov       rax, QWORD PTR [-16+rbp]
        movsx     eax, BYTE PTR [rax]
        movsx     rax, al
        xor       rax, QWORD PTR [-8+rbp]
        mov       QWORD PTR [-8+rbp], rax
        mov       eax, 1
        add       rax, QWORD PTR [-16+rbp]
        mov       QWORD PTR [-16+rbp], rax
        jmp       ..B1.2
..B1.4:
        mov       rax, QWORD PTR [-8+rbp]
        leave
        ret

This is some basic x86 assembly, but it looks like it's got some annoying things like multiplication with integer overflows and xorring, so we'll just write a C program to emulate it. Remember, rdi is the argument (which will be the address of the string), and rax is the return value.

#include <stdio.h>
#include <sys/types.h>

typedef int8_t BYTE;
typedef int16_t WORD;
typedef int32_t DWORD;
typedef int64_t QWORD;

char inp[] = "b4by_r3vers1ng_ch4ll";

int main() {
    QWORD rbp16 = (QWORD)inp;
    QWORD rbp8 = 0xcafebabe;
    QWORD rax;
    while (*(char *)rbp16) {
        rax = 0xdeadc0de;
        rax *= rbp8;
        rbp8 = rax;
        rax = *(char *)rbp16;
        rax ^= rbp8;
        rbp16++;
        rax = rbp16;
    }
    printf("%ld", rax);
}

This prints out 6295620, giving us the flag of IJCTF{6295620}.

Rev1

What does func() return?

l0rd_v0ld3m0rt:
        addiu   $sp,$sp,-24
        sw      $fp,20($sp)
        move    $fp,$sp
        sw      $4,24($fp)
        lw      $2,24($fp)
        nop
        sltu    $2,$2,2
        bne     $2,$0,$L2
        nop

        lw      $2,24($fp)
        nop
        sltu    $2,$2,3
        bne     $2,$0,$L3
        nop

        lw      $2,24($fp)
        nop
        andi    $2,$2,0x1
        bne     $2,$0,$L3
        nop

$L2:
        move    $2,$0
        b       $L4
        nop

$L3:
        lw      $3,24($fp)
        li      $2,2                        # 0x2
        bne     $3,$2,$L5
        nop

        li      $2,1                        # 0x1
        b       $L4
        nop

$L5:
        li      $2,3                        # 0x3
        sw      $2,8($fp)
        b       $L6
        nop

$L8:
        lw      $2,8($fp)
        lw      $3,24($fp)
        nop
        bne     $2,$0,1f
        divu    $0,$3,$2
        break   7
1:
        mfhi    $2
        bne     $2,$0,$L7
        nop

        move    $2,$0
        b       $L4
        nop

$L7:
        lw      $2,8($fp)
        nop
        addiu   $2,$2,2
        sw      $2,8($fp)
$L6:
        lw      $3,8($fp)
        lw      $2,8($fp)
        nop
        mult    $3,$2
        mflo    $3
        lw      $2,24($fp)
        nop
        sltu    $2,$2,$3
        beq     $2,$0,$L8
        nop

        li      $2,1                        # 0x1
$L4:
        move    $sp,$fp
        lw      $fp,20($sp)
        addiu   $sp,$sp,24
        j       $31
        nop

func:
        addiu   $sp,$sp,-40
        sw      $31,36($sp)
        sw      $fp,32($sp)
        move    $fp,$sp
        sw      $0,24($fp)
        sw      $0,28($fp)
        b       $L10
        nop

$L11:
        lw      $4,28($fp)
        jal     l0rd_v0ld3m0rt
        nop

        move    $3,$2
        lw      $2,24($fp)
        nop
        addu    $2,$2,$3
        sw      $2,24($fp)
        lw      $2,28($fp)
        nop
        addiu   $2,$2,1
        sw      $2,28($fp)
$L10:
        lw      $3,28($fp)
        li      $2,195887104                        # 0xbad0000
        ori     $2,$2,0xf00d
        sltu    $2,$3,$2
        bne     $2,$0,$L11
        nop

        lw      $2,24($fp)
        move    $sp,$fp
        lw      $31,36($sp)
        lw      $fp,32($sp)
        addiu   $sp,$sp,40
        j       $31
        nop

This is some mips assembly, and you can see inside func that 28($fp) contains a loop index and it will keep looping until it reaches 0xbadf00d, which is a really long loop. You can also see 24($fp) contains the sum of all the l0rd_v0ld3m0rt calls, which is being called with the loop index as an argument ($4 contains the argument and $2 contains the return value). In l0rd_v0ld3m0rt, we can see that L4 just returns whatever's in $2, and L2 returns 0. If our argument is less than 2, it jumps to L2 and returns 0. We can also see that L3 is where the program logic starts. If our argument, which is in 24($fp) (note that this is a different $fp than func), is less than 3 or is odd, we jump to L3, otherwise we jump to L2 and return 0. And basically there's a loop with an index stored in 8($fp) that stops when 8($fp) squared is greater than the argument. And, in each body of the loop, it takes the argument mod the index, and if it's 0 it returns 0. If it gets through the whole loop, it returns 1. So this whole thing was actually a prime checker the whole time. The goal is to find the number of primes under 0xbadf00d, which I'm sure you can figure out how to do with some googling.

Rev 2

What does prince_vegeta("sup3r_saiy4n$_4r3_c00l") return?

__SP_L__ = 0x3d
__tmp_reg__ = 0
prince_vegeta:
        push r28
        push r29
        rcall .
        rcall .
        in r28,__SP_L__
        in r29,__SP_H__
        std Y+4,r25
        std Y+3,r24
        ldd r24,Y+3
        ldd r25,Y+4
        std Y+2,r25
        std Y+1,r24
        rjmp .L2
.L3:
        ldd r24,Y+1
        ldd r25,Y+2
        adiw r24,1
        std Y+2,r25
        std Y+1,r24
.L2:
        ldd r24,Y+1
        ldd r25,Y+2
        movw r30,r24
        ld r24,Z
        tst r24
        brne .L3
        ldd r18,Y+1
        ldd r19,Y+2
        ldd r24,Y+3
        ldd r25,Y+4
        movw r20,r18
        sub r20,r24
        sbc r21,r25
        movw r24,r20
        pop __tmp_reg__
        pop __tmp_reg__
        pop __tmp_reg__
        pop __tmp_reg__
        pop r29
        pop r28
        ret

This is AVR assembly, and it's important to note that the registers are all 8 bits, and there are 16 bit pointers Y and Z, where Y is R29:R28 and Z is R31:R30. Basically, what this program does is it stores a pointer to the start of the string, then keeps incrementing another pointer until it finds the nullbyte at the end of the string, then it subtracts those two pointers and returns the difference. So, it just finds the length of the string, which is 22.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment