Table Contents


[PWN] Popping caps

Ohhh! Here we go again!

Lại là writeup của team này. Writeup rất chi tiết lại chất lượng vl. Qua đây mình học thêm kiến thức về tcache_perthread_struct cùng với [tcache house of spirit].

Sau khi free một chunk có size < 0x410 thì nó sẽ được đưa vào tcache bins. Tcachebins trong GDB sẽ có dạng như trên. Linked list , size và số chunk trong linked list được mô tả trong tcache_perthread_struct.

typedef struct tcache_entry
{
  struct tcache_entry *next;
} tcache_entry;

typedef struct tcache_perthread_struct
{
  char counts[TCACHE_MAX_BINS]; 
  tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

static __thread bool tcache_shutting_down = false;
static __thread tcache_perthread_struct *tcache = NULL;

Trong đó entries là lưu giữ node đầu của linked list ứng với mỗi size (0x10, 0x20, 0x30, …). Còn counts lưu giữ số chunk trong 1 linked list tương ứng với từng size. TCACHE_MAX_BINS = 64 và mỗi size có max là 7 tcachebins.

OK trở lại với bài này. Chương trình có 3 chức năng cơ bản malloc, free, write .

Chúng ta có lỗi double free vì con trỏ không được reset sau khi free. Đồng thời chúng ta có lỗi out of bound để có thể free bất cứ chunk nào trong heap. Lúc đầu mình không đọc kĩ lại nghĩ là free bất cứ chunk nào trong stack cơ 😆😆😆 Lỗi này giúp ta nghĩ tới house of spirit.
Đầu tiên hướng tiếp cận đơn giản sẽ là tcache dupinto stack cơ mà do nó filter số lần thực hiện có 7 lần mà phương pháp này cần ít nhất 8 lần để thực hiện. 😱😱😱 Every things are not so simple like that.

Cho nên chúng ta cần nghĩ cách rút ngắn số lượng malloc đi. Bài này cũng cho sẵn chúng ta địa chỉ hàm system rồi nên có thể thực hiện ghi đè lên __malloc_hook địa chỉ của gadget nào đó.

STAGE 1 : Create fake chunk on tcache_perthread_struct

Đầu tiên thử malloc 1 vùng nhớ size 0x40 :

Ta dùng GDB để xem tcache_perthread_struct. Ta thấy 0x557b2d5dc013 = 0x1 là số chunk tương ứng với size 0x50. Để tạo được fake chunk dùng cho house_of_spirit thì phần size của chunk phải được set tới 1 số thích hợp.
🌞 Solution : Malloc(0x3a8) -> Free.

Thì phần count tương ứng với size 0x3b0 sẽ được set. Tạo thành fake size cho target của chúng ta. Là size 0x100.

STAGE 2 : House of spirits to tcache_perthread_struct -> entries

Sau khi fake được size thì chúng ta tiến hành tính toán địa chỉ rồi free fake chunk. Chúng ta đưa được chunk đó vào tcachebins size 0x100. Sau đó malloc 1 lần nữa là ta malloc được vào vùng tcache_perthread_struct -> entries+2.

STAGE 3 : Edit with malloc_hook

Khi chúng ta có quyền ghi vào vùng tcache_perthread_struct -> entries + 2 thì tức là ta có quyền thêm con trỏ vào các free single linked list. Lúc này nếu chúng ta sửa dữ liệu vùng này thành địa chỉ malloc_hook thì trong lần malloc tiếp theo với size tướng ứng (0x20) ta sẽ có được địa chỉ của malloc_hook. Lúc này thì thoải mái ghi địa chỉ gadget và có được shell thôi.

Tại sao ta lại có size là 0x20 ? 😬😬😬 Vì chúng ta ghi malloc_hook vào phần đầu tiên của entries nên nó tương ứng với size 0x20.


[Crypto] SuperCurve

Đây là một bài Elliptic curve. Nghe ECC là sợ vl rồi. Lâu rồi mình không try hard crypto nên dạo này cảm thấy trình cùi vl.
Ok vào bài , ta có một hàm supercurve.py có những hàm cơ bản của ECC như add, mul.
Sau đó trong hàm server.py, ta phải submit giải được DLP trong ECC :

secret_scalar = random.randrange(curve.order)
  base = curve.g
  pub = curve.mult(secret_scalar, base)
  print("Public key: {}".format(pub))
  #print("Secret scalar: {}".format(secret_scalar))

  while True:
      print("What is the secret?")
      user_input = input("Asking for secret")
      user_input = int(user_input)

      if curve.mult(user_input, base) == pub:
          with open("flag.txt", "r") as f:
              print(f.read())
          break
      else:
          print("WRONGGG!")
          continue

Tuy nhiên điểm yếu ở đây là nó lấy cái secret_scalar nó lấy trong range rất nhỏ 7919. Nên có thể dễ dàng bruteforce để tìm secret. Ez ECC.


[Crypto] Fault Box

Đây là một bài RSA khá thú vị. Không nặng về toán học mà thiên về bruteforce.
Đầu tiên chúng ta có hàm gen_prime :

def gen_prime():
    base = random.getrandbits(1024)
    off = 0 
    while True:
        if gmpy2.is_prime(base + off):
            break
        off += 1
    p = base + off

    return p, off

Hàm này nó dùng hàm random của python để gen random. Lây seed là thời gian. Sau do la cac ham ma hoa :

Ta có cái hàm encrypt_test kia :)) Một hàm đúng như tên gọi của nó, nó cho ra để đánh lạc hướng người chơi với những kiến thức số học khó mà break được.
Đầu tiên chúng ta phải bruteforce y. Do y rất bé nên có thể bruteforce nhờ hàm enc_msg. Chúng ta tạo fake_flag rồi encrypt bằng hàm này. So sánh với giá trị thu được từ hàm enc_fake_flag thì ta sẽ brute được y.
Sau đó lấy enc_flag. Lưu thời gian bắt đầu và thời gian kết thúc khi nhận được enc_flag để bruteforce ít hơn.
Bước tiếp theo là tiến hành bruteforce hàm thời gian. Chúng ta tiến hàn gen p, q rồi khi nào thu được y như ta bruteforce được thì thử decrypt flag. Nếu đúng dạng của flag thì dừng không thì tiếp tục bruteforce rồi sẽ tìm được flag. Bước này tiến hành offline nên không cần quan tâm đến serve limit thời gian. 😁😁😁 Lâu ko chơi crypto nên bài đơn giản thế này cũng không nghĩ ra. Có lẽ vì mình cũng không còn quá tập trung vào crypto nữa r :))

END