]> git.somenet.org - pub/jan/ctf-seminar.git/blob - writeups/phager/otw.md
phager
[pub/jan/ctf-seminar.git] / writeups / phager / otw.md
1 # OTW Adv. 2019
2
3 Paul Theodor Hager
4 01426941
5 pH - @phager
6
7 ## Retrospective
8
9 - Was no really "impressed" by the challenges...
10 - The good ones were solved very quickly
11 - Idled on quite some channels
12
13 ## Day-19 Santa's Signature
14
15 `Can you forge Santa's signature?`
16
17 On connecton with netcat (`nc 3.93.128.89 1219`) we get the following:
18 ```
19 Dear Santa,
20 Last christmas you gave me your public key,
21 to confirm it really is you please sign three
22 different messages with your private key.
23
24 Here is the public key you gave me:
25 -----BEGIN PUBLIC KEY-----
26 <CUT>
27 -----END PUBLIC KEY-----
28 Message 1 you signed (hex encoded):
29 ```
30
31 Looking on the provided source I though the RSA looks a bit weird (=too easy). Classic secure RSA in pycryopto looks more like this: https://stackoverflow.com/a/58764650 (using `PKCS1_v1_5`).
32 Googling a bit reveals that if you use the simple `verify()` function you are using "TextBook-RSA" --> No padding --> unsecure.
33 There is a nice summary of "TextBook-RSA-Attacks": https://crypto.stackexchange.com/a/20087
34 We can see the following:
35 - signature of 0 is 0
36 - signature of 1 is 1
37 - signature of n−1 is n−1 (we have n as we get the pub key)
38
39 I started writing a script for communicating with the service and did not realize that this challenge was already solved...
40 But at least I could see that I was on the right track.
41
42 ## Day-08 Unmanaged
43
44 ```
45 I've made a Byte Buffer as a Service (BBAAS)! The service is written in C#, but to avoid performance penalties, we use unsafe code which should have comparable performance to C++!
46 ```
47 `nc 3.93.128.89 1208`
48
49 We also got the souce code.
50 On simply connecting via netcat I was not able to interact with the service.
51
52 Looking at the code one can see that its possible to send the service single byte encoded commands: allocate new byte array (with action/byte = 1), write a section of a byte array (action/byte=2) and read a section of a byte array(action/byte=3).
53 Each command has some additional parameters: index, offset and size.
54 I implemented those commands in golang (see below).
55 Analyzing the source further, we can see that no bounds checking is done and "unsafe" .NET is used, this enables unchecked pointer arithmetics in C# as like in C.
56 So we can write more or less arbitrarily (providing the "right" parameters).
57
58 I wrote a golang script which is more or less just bruteforcing the service to get any kind of output.
59
60 ```go
61 package main
62
63 import (
64         "bufio"
65         "fmt"
66         "math/rand"
67         "net"
68 )
69
70 func reader(r *bufio.Reader) {
71         for {
72                 fmt.Println("READING...")
73                 recvBuf := make([]byte, 1024)
74                 n, err := r.Read(recvBuf[:])
75                 if err != nil {
76                         fmt.Println(err)
77                         break
78                 }
79
80                 fmt.Println(n)
81                 fmt.Println(string(recvBuf))
82                 fmt.Println("-------------------------------------------------")
83         }
84
85 }
86
87 func sendAllocate(w *bufio.Writer, len byte) {
88         err := w.WriteByte(1)
89         if err != nil {
90                 fmt.Println(err)
91         }
92
93         err = w.WriteByte(len)
94         if err != nil {
95                 fmt.Println(err)
96         }
97 }
98
99 func sendWrite(w *bufio.Writer, index, offset, size byte) {
100         err := w.WriteByte(2)
101         if err != nil {
102                 fmt.Println(err)
103         }
104         err = w.WriteByte(index)
105         if err != nil {
106                 fmt.Println(err)
107         }
108         err = w.WriteByte(offset)
109         if err != nil {
110                 fmt.Println(err)
111         }
112         err = w.WriteByte(size)
113         if err != nil {
114                 fmt.Println(err)
115         }
116 }
117
118 func sendRead(w *bufio.Writer, index, offset, size byte) {
119         err := w.WriteByte(3)
120         if err != nil {
121                 fmt.Println(err)
122         }
123         err = w.WriteByte(index)
124         if err != nil {
125                 fmt.Println(err)
126         }
127         err = w.WriteByte(offset)
128         if err != nil {
129                 fmt.Println(err)
130         }
131         err = w.WriteByte(size)
132         if err != nil {
133                 fmt.Println(err)
134         }
135 }
136
137 func sendByte(w *bufio.Writer, c byte) error {
138         err := w.WriteByte(c)
139         if err != nil {
140                 fmt.Println(err)
141                 return err
142         }
143         return nil
144 }
145
146 func main() {
147         conn, _ := net.Dial("tcp", "3.93.128.89:1208")
148         defer conn.Close()
149
150         r := bufio.NewReader(conn)
151         go reader(r)
152
153         w := bufio.NewWriter(conn)
154
155         //sendAllocate(w, 100)
156         //sendWrite(w, 10, 0, 100)
157         //sendWrite(w, 60, 0, 100)
158         //sendWrite(w, 100, 0, 100)
159         //sendWrite(w, 255, 0, 100)
160
161         sendAllocate(w, 1)
162
163         rand.Seed(42)
164         for i := 0; i < 1500; i++ {
165                 sendWrite(w, 0, byte(rand.Intn(255)), byte(rand.Intn(255)))
166         }
167
168         fmt.Println("done")
169
170         select {}
171
172 }
173
174 ```
175
176 My goal was to somehow get a basic understanding of how the "actions" are working and to push shellcode somewhere to execute it later.
177 As I had to go afk, I pinged @dachleitner to solve it - and he did before I was back.
178