[3DS CTF] [MISC 400 – WAT] Write up

Description

[EN]
Scavenging an old 318br repo, we found a program missing some line of code. Even without this line, we would like to know the result of
its execution.
Specific instruction: Put the flag on the format 3DS{} and submit.

[PT]
Vasculhando um repositorio antigo do 318br, nos encontramos um programa faltando uma parte. Mesmo faltando uma parte, nos gostariamos que voce nos dissesse o resultado de sua execucao.
Instrucao especifica: Colocar o resultado no formato 3DS{} e submeter.

Solved by 19 Teams

Resolution

The given zip file contains 33 files like this:

****************** Third Development Software Company for DEC9 *********************
    0        1         2         3         4         5         6         7         8
    12345678901234567890123456789012345678901234567890123456789012345678901234567890
    ________________________________________________________________________________
12 /O                                                                               
11|X                                                                                
 0|X                                                                                
 1|X  O                                                                             
 2|X    O                                                                           
 3|XO     O                                                                         
 4|X        O                                                                       
 5|X                                                                                
 6|X                                                                                
 7|X                                                                                
 8|X                                                                                
 9|X                                                                                
  |_________________________________________________________________________________

It a simple Punched Card like this one:

How does it works? It’s very simple!

    _________
12 /O                                                                               
11|X                                                                                
 0|X                                                                                
 1|X  O                                                                             
 2|X    O                                                                           
 3|XO     O  

The 2 first raws (12 and 11) are kind of “multiplier factor”, and the others (0-9) are the values.

  • In the first column there are 2 holes (the O) : one at the raw 12, one at the raw 3.
    The raw 12 adds 10 to the result 2, so for the first column it gave 12.
  • The second column there’s 1 hole in the raw 1, so it gave 1.

As the simplified charset is : 0-9, A-Z, we can deduce that 12 is a C, 1 is 1 etc. so the card was “C123” 🙂

The real charsets are:

029  &-0123456789ABCDEFGHIJKLMNOPQR/STUVWXYZ:#@'="¢.<(+|!$*);¬ ,%_>?
IBME ¹-0123456789ABCDEFGHIJKLMNOPQR/STUVWXYZ:#²'="].<(+|[$*);¬³,%_>?
EBCD &-0123456789ABCDEFGHIJKLMNOPQR/STUVWXYZ:#@'="[.<(+|]$*);^\,%_>?

A basic representation of the conversion:

12 value:  [      not holed    |       holed     ]
11 value:  [              not holed              |      holed      ]
0-9 value: [0|1|2|3|4|5|6|7|8|9|1|2|3|4|5|6|7|8|9|1|2|3|4|5|6|7|8|9]
ASCII res: [0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R]

For the rest of the letters and special chars, it’s a little bit more complex.
You can refer to the script below.

The 3rd card was complex to handle manually:

****************** Third Development Software Company for DEC9 *********************
    0        1         2         3         4         5         6         7         8
    12345678901234567890123456789012345678901234567890123456789012345678901234567890
    ________________________________________________________________________________
12 /         O O    O                                                               
11|X      OOO O O OO OO                                                             
 0|X                                                                                
 1|X           O                                                                    
 2|X                                                                                
 3|X                                                                                
 4|X            O     O                                                             
 5|X                                                                                
 6|X        O                                                                       
 7|X      O  O    O O                                                               
 8|X                                                                                
 9|X       O  O    O O                                                              
  |_________________________________________________________________________________

1st column: 11 is holed + 7 = P
2nd column: 11 is holed + 9 = R
3rd column: 11 is holed + 6 = O
4th column: 12 is holed + 7 = G
5th column: 11 is holed + 9 = R
6th column: 12 is holed + 1 = A
7th column: 11 is holed + 4 = M
etc.
Giving PROGRAM PRGRM

It’s an instruction in Fortran.

As decoding all the cards is quite boring, we made a script to do that:

#!/usr/bin/python2
# Based on a write up for the Boston Key Party CTF 2015, task Haymarket
def decode(code):
    if code == ['0']: return '0'
    elif code == ['1']: return '1'
    elif code == ['2']: return '2'
    elif code == ['3']: return '3'
    elif code == ['4']: return '4'
    elif code == ['5']: return '5'
    elif code == ['6']: return '6'
    elif code == ['7']: return '7'
    elif code == ['8']: return '8'
    elif code == ['9']: return '9'
    elif code == ['12', '1']: return 'A'
    elif code == ['12', '2']: return 'B'
    elif code == ['12', '3']: return 'C'
    elif code == ['12', '4']: return 'D'
    elif code == ['12', '5']: return 'E'
    elif code == ['12', '6']: return 'F'
    elif code == ['12', '7']: return 'G'
    elif code == ['12', '8']: return 'H'
    elif code == ['12', '9']: return 'I'
    elif code == ['11', '1']: return 'J'
    elif code == ['11', '2']: return 'K'
    elif code == ['11', '3']: return 'L'
    elif code == ['11', '4']: return 'M'
    elif code == ['11', '5']: return 'N'
    elif code == ['11', '6']: return 'O'
    elif code == ['11', '7']: return 'P'
    elif code == ['11', '8']: return 'Q'
    elif code == ['11', '9']: return 'R'
    elif code == ['0', '1']: return '/'
    elif code == ['0', '2']: return 'S'
    elif code == ['0', '3']: return 'T'
    elif code == ['0', '4']: return 'U'
    elif code == ['0', '5']: return 'V'
    elif code == ['0', '6']: return 'W'
    elif code == ['0', '7']: return 'X'
    elif code == ['0', '8']: return 'Y'
    elif code == ['0', '9']: return 'Z'
    elif code == ['11', '2', '8']: return '!'
    elif code == ['4', '8']: return '@'
    elif code == ['3', '8']: return '#'
    elif code == ['11', '3', '8']: return '$'
    elif code == ['0', '4', '8']: return '%'
    elif code == ['12', '7', '8']: return '^'
    elif code == ['12']: return '&'
    elif code == ['11', '4', '8']: return '*'
    elif code == ['12', '5', '8']: return '('
    elif code == ['11', '5', '8']: return ')'
    elif code == ['11']: return '-'
    elif code == ['6', '8']: return '='
    elif code == ['0', '5', '8']: return '_'
    elif code == ['0', '3', '8']: return ','
    elif code == ['12', '6', '8']: return '+'
    elif code == ['12', '2', '8']: return '['
    elif code == ['0', '2', '8']: return '['
    elif code == ['11', '6', '8']: return ';'
    elif code == ['0', '6', '8']: return '>'
    elif code == ['5', '8']: return "'"
    elif code == ['2', '8']: return ':'
    elif code == ['7', '8']: return '"'
    elif code == ['11', '7', '8']: return ' '
    elif code == ['12', '3', '8']: return '.'
    elif code == ['12', '4', '8']: return '<'
    else: return '?'

lines = list()
for num in range(1,34):
    card = "card-" + str(format(num,'02')) + "-34.dec"
    file = open(card, "r")
    for line in file:
          lines.append(line)
    code = []
    text = ""
    for c in range (80):
        for r in range (12):
            if lines[r+4][c+3] == "O":
                if r==0:
                    code.append('12')
                if r==1:
                    code.append('11')
                if r!=0 and r!=1:
                    code.append(str(r-2))
        if len(code) > 0:
            text += decode(code)
            code = []
    print text
    lines = []
    file.close()

Giving us:

C1234
C234567890123456789012345678901234567890
PROGRAMPRGRM
INTEGERC,X
DOUBLEPRECISIONI,R,A
DOUBLEPRECISIONRES
GOTO1598
1599A=1/RES
GOTO2852
0666GOTO0665
7599A=-1/RES
GOTO2852
1598C=1337
RES=1
X=0
1337X=X
GOTO5523
0318I=I*4
PRINT*,I
GOTO0666
5523IF(MOD(X,2).EQ.0)THEN
GOTO1599
ELSE
GOTO7599
ENDIF
2852I=I+A
GOTO9513
9513RES=RES+2
X=X+1
IF(X.EQ.C)THEN
GOTO0318
ENDIF
GOTO1337

As they told in the task description, there was some code missing:
0666 GOTO 0665, but there’s no 0665, no “END PROGRAM” etc.

We modified the code to:

!C1234
!C234567890123456789012345678901234567890
PROGRAM PRGRM
INTEGER C,X
DOUBLE PRECISION I,R,A
DOUBLE PRECISION RES
GOTO 1598
1599 A=1/RES
GOTO 2852
666 GOTO 665
7599 A=-1/RES
GOTO 2852
1598 C=1337
RES=1
X=0
1337 X=X
GOTO 5523
318 I=I*4
PRINT *,I
GOTO 666
5523 IF(MOD(X,2).EQ.0) THEN
GOTO 1599
ELSE
GOTO 7599
ENDIF
2852 I=I+A
GOTO 9513
9513 RES=RES+2
X=X+1
IF(X.EQ.C)THEN
GOTO 318
ENDIF
GOTO 1337
665 STOP
END PROGRAM

Then executed it on an online interpreter: https://www.jdoodle.com/execute-fortran-online.

Note: The following floating-point exceptions are signalling: IEEE_DENORMAL
   3.1423405966415094

Flag was 3DS{3.1423405966415094}

Leave a Reply

Your email address will not be published. Required fields are marked *