Writeup 2026_0827

wrong instruction - AlpacaHack
binary ninjaでごちゃごちゃやった気がしますので、また後で書きます。

Flag is A+B - AlpacaHack
A or BとA xor Bの値だけわかるので、A+Bの値を復元する。
A + B = A xor B + 2 * (A and B)で、
A and B = A or B - A xor Bなので、
A + B = A xor B + 2 * (A or B - A xor B)

1
2
3
4
5
6
7
OR = 1708520672692343497693425015709016883325158039728511260268583494549501
XOR = 1653224853895272618878301831150773792186632776885840473347068872416893

n = 2 * OR - XOR

flag = n.to_bytes((n.bit_length() + 7) // 8, "big").decode()
print(flag)

func-array - AlpacaHack

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
#include <stdio.h>
#include <stdlib.h>

void alpaca_function0() {
puts("Alpaca Function 0.");
}

void alpaca_function1() {
puts("Alpaca Function 1. 🦙");
}

void alpaca_function2() {
puts("Alpaca Function 2. 🦙🦙");
}

void win() {
asm volatile("mov $0,%spl");
puts("You Win! 🦙🦙🦙🦙🦙");
system("/bin/sh");
exit(0);
}

void vuln() {
void (*alpaca_functions[3])() = {
alpaca_function0,
alpaca_function1,
alpaca_function2};

unsigned int choice;
printf("Select an alpaca function index: ");
scanf("%u", &choice);

alpaca_functions[choice]();

exit(0);
}

int main() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);

vuln();

win();

return 0;
}

choiceの値をいい感じにして、win()を実行する。

objdumpすると

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
0000000000401257 <vuln>:
401257: f3 0f 1e fa endbr64
40125b: 55 push %rbp
40125c: 48 89 e5 mov %rsp,%rbp
40125f: 48 83 ec 30 sub $0x30,%rsp
401263: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
40126a: 00 00
40126c: 48 89 45 f8 mov %rax,-0x8(%rbp)
401270: 31 c0 xor %eax,%eax
401272: 48 8d 05 5d ff ff ff lea -0xa3(%rip),%rax # 4011d6 <alpaca_function0>
401279: 48 89 45 e0 mov %rax,-0x20(%rbp)
40127d: 48 8d 05 6c ff ff ff lea -0x94(%rip),%rax # 4011f0 <alpaca_function1>
401284: 48 89 45 e8 mov %rax,-0x18(%rbp)
401288: 48 8d 05 7b ff ff ff lea -0x85(%rip),%rax # 40120a <alpaca_function2>
40128f: 48 89 45 f0 mov %rax,-0x10(%rbp)
401293: 48 8d 05 de 0d 00 00 lea 0xdde(%rip),%rax # 402078 <_IO_stdin_used+0x78>
40129a: 48 89 c7 mov %rax,%rdi
40129d: b8 00 00 00 00 mov $0x0,%eax
4012a2: e8 09 fe ff ff call 4010b0 <printf@plt>
4012a7: 48 8d 45 dc lea -0x24(%rbp),%rax
4012ab: 48 89 c6 mov %rax,%rsi
4012ae: 48 8d 05 e5 0d 00 00 lea 0xde5(%rip),%rax # 40209a <_IO_stdin_used+0x9a>
4012b5: 48 89 c7 mov %rax,%rdi
4012b8: b8 00 00 00 00 mov $0x0,%eax
4012bd: e8 0e fe ff ff call 4010d0 <__isoc99_scanf@plt>
4012c2: 8b 45 dc mov -0x24(%rbp),%eax
4012c5: 89 c0 mov %eax,%eax
4012c7: 48 8b 54 c5 e0 mov -0x20(%rbp,%rax,8),%rdx
4012cc: b8 00 00 00 00 mov $0x0,%eax
4012d1: ff d2 call *%rdx
4012d3: bf 00 00 00 00 mov $0x0,%edi
4012d8: e8 03 fe ff ff call 4010e0 <exit@plt>

で、
スタック配置は以下のようになっています。

1
2
3
4
5
6
7
[rbp + 0x08] return adress
[rbp] 呼び出し元のrbp
[rbp - 0x08] stack canary
[rbp - 0x10] alpaca2への関数ポインタ
[rbp - 0x18] alpaca1への関数ポインタ
[rbp - 0x20] alpaca0への関数ポインタ
[rbp - 0x24] scanfで読み込んだ値
1
2
mov -0x20(%rbp,%rax,8), %rdx 
call *%rdx

rbp - 0x20 + input * 8で計算した値を関数アドレスとして呼び出している。
rbp - 0x20 + input * 8をrbp + 0x08にできれば、main()内のwin()を実行することができそう。
rbp - 0x20 + input * 8 = rbp + 0x08を計算すると
input = 5なので、5を入れる。

glibc’s secret function - AlpacaHack

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
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

const unsigned char expected[97] = {107, 70, 90, 75, 73, 75, 81, 126, 66, 67, 89, 117, 67, 89, 117, 94, 66, 79, 117, 0, 103, 115, 121, 126, 111, 120, 99, 101, 127, 121, 117, 75, 68, 78, 117, 125, 101, 100, 110, 111, 120, 108, 127, 102, 0, 117, 76, 95, 68, 73, 94, 67, 69, 68, 117, 67, 68, 117, 77, 70, 67, 72, 73, 11, 117, 107, 70, 89, 69, 117, 66, 69, 93, 117, 75, 72, 69, 95, 94, 117, 89, 94, 88, 76, 88, 83, 117, 76, 95, 68, 73, 94, 67, 69, 68, 21, 87};

int main()
{
char input[112], work[112];
printf("Input > ");
scanf("%111s", input);

size_t len = strlen(input);
if (len == sizeof(expected))
{
strcpy(work, input);
memfrob(work, len);
if(!memcmp(work, expected, sizeof(expected)))
{
printf("Correct! The flag is %s\n", input);
return 0;
}
}
printf("Incorrect...\n");
return 1;
}

memfrob(void *mem, size_t length)が、mem からはじまる length バイトの領域に対し、1 バイトごとに 42 との排他的論理和を計算して上書きするものらしいので、
expectedに対しても同じことをするとフラグを取得できました。

Author

kiku

Posted on

2026-08-28

Updated on

2026-08-28

Licensed under