pawnfish

# Description

Info:
Fishes are pretty good at chess. nc pawnfish.chal.uiuc.tf 1337
File: handout.tar.gz

TL;DR:
Look around the source code => We have to win 100 times and the current_player is Black to get the flag.
wins variable is signed char => We can lose a lot in order to make wins equals to 100, but what about current_player?
We have to win a game to turn current_player to Black. The file also use stockfish engine => Can’t win easily, we have to find some bugs and take those advantages to win.
Find En Passant bugs => Find a way to win, put all the things together to get the flag.

# Plan

First of all, I think this is more like a Misc than RE challenge, because you need quite chess knowledges to solve this challenge.
The file gave us source code and some files related to chess stuff, so I just check chal.c. This is a very long source code, I immidiately check the condition to get the flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if (current_player == Black) {
	FILE* flag;
	int c;
	flag = fopen("flag.txt", "r");
	if (flag) {
		while ((c = getc(flag)) != EOF) {
			putchar(c);
		}
		putchar('\n');
		fclose(flag);
	} else {
		puts("Flag is missing :/");
	}
} else {
	puts("How is this possible?? You didn't win the 100th game!");
	puts("I won't stand a cheater!!!");
	exit(96);
}

And looking around main functions. I know that we also need to make wins equals 100 to escape the while loop and come to our check condition:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main() {
...
while (wins != 100 || current_player == White) {
...
if (current_player == Black) {
	FILE* flag;
	int c;
	flag = fopen("flag.txt", "r");
	if (flag) {
		while ((c = getc(flag)) != EOF) {
			putchar(c);
		}
		putchar('\n');
		fclose(flag);
	}
...

For the wins condition, we just need to lose a lot, enough to make the wins equals to 100, that’s the easy part. The hard part is to make current_player equals to Black. In order to do that, we have to win a game. But this is stockfish engine, you need Hikaru Nakamura to defeat this to get us the flag. After a while, I think there has to be some bugs around…

# The Bug

… and indeed, there is. After spending a lot of time to debug, my teammate find the En Passant flaw: the En Passant is meant to apply just for pawn. But for some weird reasons, this program applies En Passant to literally every chess pieces.

Chess

This is huge, we can slowly build our way to defeat this engine. After several tries, we finally win one game, and using everything we’ve known so far to write a script:

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
from pwn import *

p = remote('pawnfish.chal.uiuc.tf', 1337)

def send_piece(mov1, mov2):
	p.recv()
	p.sendline(mov1)
	p.recv()
	p.sendline(mov2)

for i in range(157):
	print(i)
	send_piece('e2','e4')
	send_piece('e1','e2')
	send_piece('e2','e3')
	send_piece('e3','f4')
	send_piece('f4','e5')
	p.recvuntil('lose')
	p.recvline()

send_piece('e2','e4')
send_piece('c2','c3')
send_piece('e4','e5')
send_piece('e5','d6')
send_piece('g1','f3')
send_piece('d2','d4')
send_piece('c3','d4')
send_piece('d4','e5')
send_piece('f1','e2')
send_piece('e1','g1')
send_piece('e5','d6')
send_piece('h2','h3')
send_piece('e2','f3')
send_piece('d6','c7')
send_piece('f1','e1')
send_piece('c1','e3')
send_piece('d1','e2')
send_piece('e3','c5')
send_piece('e2','e7')
send_piece('e1','e7')
send_piece('e7','a7')
send_piece('a2','a4')
send_piece('a4','b5')
send_piece('b1','c3')
send_piece('b5','b6')
send_piece('b6','b7')
send_piece('a7','a8')
send_piece('f3','b7')
send_piece('a1','b1')
send_piece('b2','b4')
send_piece('c3','a2')
send_piece('b4','b5')
send_piece('b5','b6')
send_piece('a8','a7')
send_piece('a2','c3')
send_piece('c3','d5')
send_piece('d5','e7')
send_piece('e7','c6')
send_piece('b6','b7')
send_piece('h3','g4')
send_piece('g4','f5')
send_piece('b7','b8')
send_piece('b1','b8')
send_piece('g1','h2')
send_piece('b8','f8')
send_piece('f5','f6')
send_piece('h2','h3')
send_piece('g2','g4')
send_piece('h3','g3')
send_piece('c6','e7')
send_piece('f8','d8')
send_piece('a7','c7')
send_piece('e7','d5')
send_piece('d8','b8')
send_piece('f6','f7')
send_piece('c7','a7')

p.interactive()

And the answer:

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
$ python3 solve.py
[+] Opening connection to pawnfish.chal.uiuc.tf on port 1337: Done
0
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
[*] Switching to interactive mode
Location to > Moving WHITE  from row: 1, col: 2, TO row: 1, col: 0
You win :)
uiuctf{strange_the_only_winning_move_is_to_lose}

uiuctf{strange_the_only_winning_move_is_to_lose}