- GPT5.6 Sol Ultra đã phân tích phiên bản ổn định mới nhất của WordPress và hoàn thiện một chuỗi tấn công từ SQL injection trước xác thực đến tạo tài khoản quản trị viên và thực thi mã từ xa (RCE) chỉ trong khoảng hơn 10 giờ
- Điểm xuất phát là sự không khớp chỉ mục mảng trong Batch API có từ WordPress 5.6; bằng cách kết hợp các yêu cầu Batch đệ quy, nó vượt qua giới hạn GET và kiểm tra tham số
- Sau khi gây UNION injection bằng chuỗi
author_excludechưa được kiểm tra, chuỗi này đưa bài viết đã thao túng vào bộ nhớ đệm trong RAM rồi lần lượt lạm dụng oEmbed cache, changeset, tham chiếu vòng và hook - Với
user_id: 1trongcustomize_changeset, nó tạm thời giành quyền quản trị viên, dùng hookparse_requestđể chạy lại yêu cầu Batch nhằm tạo quản trị viên mới, rồi tải lên ZIP plugin backdoor để đạt được thực thi mã - Chi phí tính theo tỷ lệ 50% hạn mức sử dụng hằng tuần của gói thuê bao 200 đô la/tháng là khoảng 25 đô la; vai trò của con người có khả năng sẽ chuyển sang chỉ đạo nghiên cứu ở cấp cao hơn như chọn sản phẩm, bề mặt tấn công và tinh chỉnh prompt
Quá trình phát hiện và điều kiện thử nghiệm
- Prompt mà OpenAI công bố là đã dùng để giải quyết giả thuyết Cycle Double Cover được sửa đổi cho nghiên cứu bảo mật và đưa cho GPT5.6 Sol Ultra
- Sao chép phiên bản ổn định mới nhất của WordPress vào
main/, xóa thư mục.git, đồng thời chuẩn bị một thư mụcthird_party/rỗng để có thể khảo sát mã phụ thuộc - Prompt yêu cầu dùng tối đa 4 agent chạy song song và duy trì nhiều hướng tấn công khác nhau trong ít nhất 6 giờ
- Khám phá parsing đầu vào, bộ ký tự, tải tệp lên, xử lý lỗi, đường dẫn tích hợp, serialization, cache, race condition, mã hóa, kiểu dữ liệu, mass assignment, v.v.
- Ghi nhận các họ cách tiếp cận; nếu agent dồn vào một chiến lược cụ thể thì phân bổ lại sang những vùng ít được khám phá hơn
- Các lỗi cụ thể được agent đối kháng xác minh lại, và cả những hướng đã thất bại cũng được mở lại nếu xuất hiện cơ chế mới
- Bị giới hạn phải tìm lỗ hổng mới từ chính mã nguồn, không dùng lịch sử thay đổi, khác biệt với bản vá hay manh mối trên Internet
- Để tránh cấu hình phi thực tế hoặc tiền đề mà kẻ tấn công không thể đáp ứng, mục tiêu được nêu rõ là “RCE trước xác thực trên triển khai production thông thường dùng MySQL”
- Sau khoảng 6 giờ, mô hình tìm ra SQL injection trước xác thực; việc tái hiện trên máy chủ WordPress từ xa mặc định đã trích xuất email quản trị viên trong vài phút
- Khi yêu cầu nâng cấp lên RCE, khoảng 4 giờ sau mô hình hoàn thiện chuỗi từ SQL injection chỉ đọc lên quyền quản trị viên mà không cần cracking mật khẩu hay tính toán offline
- Tổng thời gian làm việc là hơn 10 giờ một chút, tiêu thụ 50% hạn mức hằng tuần. Chi phí tính tỷ lệ từ gói thuê bao 200 đô la/tháng là khoảng 25 đô la
- Trước khi công bố, người vận hành được cho thời gian cuối tuần để nâng cấp WordPress; trong thời gian đó Calif và Hacktron đã tái hiện độc lập toàn bộ chuỗi trước các PoC khác trên GitHub
- Các instance đang vận hành có thể kiểm tra khả năng bị ảnh hưởng tại wp2shell.com
Sự không khớp kiểm tra trong Batch API
- Batch API được giới thiệu trong WordPress 5.6 xử lý nhiều yêu cầu API ảo trong một yêu cầu duy nhất. Bản thân endpoint có thể truy cập không cần xác thực, nhưng thông tin xác thực được truyền cho từng yêu cầu con
- Một yêu cầu REST thông thường được xử lý theo thứ tự sau
- Kiểm tra giá trị bắt buộc và tính hợp lệ bằng
has_valid_params() - Làm sạch giá trị bằng
sanitize_params() - Chạy callback phân quyền
- Chạy callback endpoint
- Kiểm tra giá trị bắt buộc và tính hợp lệ bằng
- Vì hiệu năng, Batch API tách kiểm tra và thực thi thành hai vòng lặp
- Vòng lặp đầu tiên kiểm tra và làm sạch tất cả yêu cầu
- Vòng lặp thứ hai kiểm tra kết quả kiểm tra rồi chạy callback phân quyền và endpoint
- Phần triển khai giả định các chỉ mục tương ứng trong
$matches, kết quả khớp route, và$validation, kết quả kiểm tra - Nếu một yêu cầu sai đi vào nhánh
is_wp_error($single_request), một mục được thêm vào$validation, nhưng docontinuenên không được thêm vào$matches- Sau đó mọi mục trong
$matchesbị lệch một ô - Có thể kiểm tra tham số của một yêu cầu bằng quy tắc của yêu cầu khác, rồi thực thi trong handler endpoint vốn không được dự định
- Sau đó mọi mục trong
- Bằng cách lợi dụng sự không khớp chỉ mục này, có thể áp dụng kết quả kiểm tra của một endpoint khác không làm sạch tham số lên endpoint hỗ trợ Batch
SQL injection phát sinh từ author__not_in
GET /wp/v2/postsdùng biến truy vấn nội bộauthor__not_inđể loại trừ một số tác giả khỏi kết quả- Nếu giá trị là mảng, từng phần tử được áp dụng
absintđể chuyển thành số nguyên; nhưng nếu là giá trị vô hướng thì đượcimplodenguyên dạng rồi chèn vào mệnh đềNOT INcủa SQL - Khi gọi bình thường, tham số công khai
author_excludephải là mảng số nguyên nên vấn đề không lộ ra - Lợi dụng sự không khớp chỉ mục Batch, có thể kiểm tra chuỗi
author_excludebằng quy tắcDELETE /wp/v2/posts/1, vốn không nhận biết nó, rồi truyền sangGET /wp/v2/posts - Ràng buộc Batch API không cho phép yêu cầu con GET cũng được vượt qua bằng lời gọi Batch đệ quy
- Ở Batch bên ngoài, gây lệch chỉ mục để bỏ qua kiểm tra
methodcủa yêu cầu bên trong - Ở Batch bên trong, lại gây lệch chỉ mục để vượt qua kiểm tra
author_exclude
- Ở Batch bên ngoài, gây lệch chỉ mục để bỏ qua kiểm tra
- Chèn giá trị như
0) OR 1=1 --sẽ trả về tất cả hàng bài viết, qua đó xác nhận có injection - Sau đó có thể dùng UNION-based injection để tạo hàng có cùng dạng với
wp_postsvà rò rỉ giá trị cơ sở dữ liệu tùy ý - Mật khẩu, token đặt lại, API key, v.v. được hash trong cơ sở dữ liệu, nên nếu mật khẩu quản trị viên không yếu thì chỉ rò rỉ dữ liệu chưa đủ để chiếm tài khoản
Thao túng cache bài viết trong một yêu cầu
- WordPress lưu các đối tượng
WP_Postđược tham chiếu lặp lại trong cùng một yêu cầu vào cache trong bộ nhớ để giảm lượt truy cập cơ sở dữ liệu - Nếu trả về hàng bài viết giả bằng UNION injection, kẻ tấn công có thể đưa vào cache nhiều trường do mình định sẵn như ID bài viết, kiểu, trạng thái, quan hệ cha, nội dung, v.v.
- Phản hồi API cũng hậu xử lý nội dung bài viết, nên nội dung bị thao túng có thể kích hoạt thêm các đường đi mã khác
- Cache này biến mất khi yêu cầu kết thúc và bài viết giả cũng không tồn tại trong cơ sở dữ liệu, nên chỉ thao túng cache thì không thể bảo đảm tính tồn tại giữa các yêu cầu
Tạo hàng cơ sở dữ liệu bằng oEmbed cache
- Tính năng embeds của WordPress chèn nội dung từ xa được hỗ trợ bằng cú pháp
[embed]...[/embed]trong nội dung bài viết - Để tránh gửi HTTP request mỗi lần, kết quả được lưu vào cơ sở dữ liệu dưới dạng bài viết kiểu
oembed_cachetrongwp_posts - Nếu embed một bài viết WordPress cục bộ bằng đường dẫn tương đối, HTTP request sẽ bị bỏ qua và không kiểm tra ID bài viết được tham chiếu có thực sự tồn tại hay không
- Ngay cả khi embed bài viết cục bộ không tồn tại như
/?p=10, một hàngoembed_cachecho dữ liệu đó vẫn có thể được tạo - Khi truy vấn lại hàng đã tạo bằng SQL injection và thao túng kiểu bài viết trong bộ nhớ thành
posthay tương tự, biểu diễn trong cơ sở dữ liệu và trong cache sẽ khác nhau - Khi điều hòa hai biểu diễn này, WordPress gọi
wp_update_post(), và với các trường ngoàiIDvàpost_contentđược chỉ định rõ, nó ưu tiên các giá trị trong bộ nhớ do kẻ tấn công tạo - Nhờ đó có thể đổi hàng
oembed_cachethành bài viết thông thường, nhưng trong lời gọi nàypost_contentbị ghi đè bằng kết quả embed nên kẻ tấn công chưa kiểm soát được cả nội dung
Quyền quản trị viên tạm thời qua customize_changeset
- Bản nháp thao tác tùy biến giao diện được lưu trong
wp_postsdưới dạng bài viết đặc biệt kiểucustomize_changeset post_contentchứa JSON gồm giá trị thay đổi theo từng khóa thiết lập, kiểu dữ liệu và ID người dùng thực hiện thay đổi- Khi áp dụng changeset, WordPress đọc
user_idcủa từng mục và tạm thời đổi người dùng hiện tại bằngwp_set_current_user() - Nếu kẻ tấn công áp dụng changeset có
user_id: 1, họ có thể tạm thời dùng danh tính quản trị viên ngay cả trong yêu cầu ẩn danh - Lời gọi điều hòa oEmbed ở trên ghi đè
post_content, nên cần một đường gọiwp_update_post()riêng để bảo toàn JSON changeset độc hại
Bảo toàn nội dung bằng vòng lặp cha của bài viết
- Bài viết WordPress có thể có một cha, nhưng không cho phép cấu trúc vòng lặp trong đó cha là chính nó hoặc bài viết con
- Filter
wp_insert_post_parentđi theo cây cha để kiểm tra vòng lặp; nếu phát hiện vòng lặp, nó gọiwp_update_post()để đổipost_parentcủa bài viết đó thành 0 - Lời gọi thứ hai này chỉ chỉ định
IDvàpost_parent, không ghi đèpost_content - Nếu dùng SQL injection để ngụy trang bài viết trong bộ nhớ thành
customize_changesetcó cha là chính nó, quá trình khôi phục vòng lặp sẽ ghi JSON changeset độc hại do kẻ tấn công chỉ định vào cơ sở dữ liệu - Tạo changeset có trạng thái
futurenhưng ngày trong quá khứ sẽ khiến WordPress áp dụng nó, và theouser_id: 1thực hiện thay đổi thiết lập được chỉ định với quyền quản trị viên - Quyền quản trị viên chỉ tồn tại trong khi xử lý changeset; sau khi hoàn tất sẽ trở lại quyền khách
Chạy lại toàn bộ yêu cầu bằng hook động
- Hook của WordPress được chia thành action và filter, cho phép plugin can thiệp vào nhiều điểm trong vòng đời như đăng nhập, đăng bài, đăng ký script, v.v.
- Khi trạng thái bài viết thay đổi, WordPress thực thi action động dạng
"{$new_status}_{$post->post_type}"- Với bài viết bình thường, tên sẽ như
publish_post - Với bài viết giả trong bộ nhớ, có thể tùy ý đặt trạng thái và kiểu, từ đó tạo tên action mong muốn có ít nhất một dấu gạch dưới
- Với bài viết bình thường, tên sẽ như
- Đối số hook bị giới hạn ở ID bài viết do kẻ tấn công đặt và đối tượng
WP_Post, nên khó gọi trực tiếp một action tùy ý theo cách hữu dụng - Chuỗi tấn công thao túng trạng thái thành
parsevà kiểu thànhrequestđể gọi hookparse_request parse_requestlà hook chạy ở giai đoạn đầu vòng đời yêu cầu, nên gọi lại nó sẽ khiến toàn bộ yêu cầu Batch API ban đầu được xử lý lại từ đầu- Việc xử lý lại diễn ra khi danh tính quản trị viên tạm thời do changeset thiết lập vẫn còn hiệu lực, nên yêu cầu chỉ dành cho quản trị viên thất bại vì thiếu quyền ở lần chạy đầu sẽ thành công ở lần chạy thứ hai
Chuỗi RCE hoàn chỉnh bằng hai yêu cầu
- Exploit cuối cùng dùng hai HTTP request và gán cho bài viết giả một ID đủ lớn để không xung đột với bài viết thật
-
Yêu cầu thứ nhất: chuẩn bị hàng tồn tại lâu dài
- Trả về một bài viết giả có ba embed cục bộ bằng SQL injection, tạo 3 hàng
oembed_cachetương ứng vớiO,C,D - Ba embed trỏ đến cùng bài viết
Snhưng dùng chuỗi truy vấn khác nhau để tạo các hash oEmbed cache riêng biệt
- Trả về một bài viết giả có ba embed cục bộ bằng SQL injection, tạo 3 hàng
-
Yêu cầu thứ hai: lắp ghép sáu bài viết
- Cấu hình sáu bài viết giả sau trong cache bộ nhớ
O: cache cũ có trạng thái/kiểu làpublish/oembed_cachevà cha làCC: có trạng thái/kiểu làfuture/customize_changeset, cha là chính nó và chứa JSON changeset độc hạiP:draft/pagecó cha làDD: có trạng thái/kiểu làparse/requestvà cha là chính nóS:publish/postcung cấp dữ liệu embedT:publish/postchứa embed bên ngoài- Embed của
Ttruy vấnO, và do thời điểm sửa đổi cũ, buộc cache củaSđược làm mới - Trong quá trình cập nhật
O, nếu phát hiện vòng lặp ở chaC, nó đổi cha củaCthành 0 và ghicustomize_changesettrong bộ nhớ cùng JSON độc hại vào cơ sở dữ liệu - Changeset
futurecó ngày trong quá khứ được áp dụng, đăngPdưới danh tính quản trị viênuser_id: 1 - Việc cập nhật
Pphát hiện vòng lặp ở chaD, ghiD, rồi với trạng thái và kiểu bị thao túng, gọi actionparse_request - Yêu cầu Batch ngay từ đầu đã bao gồm yêu cầu tạo quản trị viên mới
- Lần xử lý đầu thất bại vì đang ở quyền khách
- Khi chạy lại qua
parse_request, quyền quản trị viên tạm thời vẫn còn nên yêu cầu thành công - Sau khi đăng nhập bằng tài khoản quản trị viên mới, tải lên ZIP plugin backdoor để cuối cùng đạt được thực thi mã từ xa
Vai trò thay đổi trong nghiên cứu bảo mật bằng AI
- Những bước đặc biệt sáng tạo trong toàn chuỗi là vượt qua giới hạn GET bằng lời gọi Batch đệ quy, kết hợp cache với changeset để lấy quyền quản trị viên, và gọi
parse_requestbằng bài viết giả để chạy lại yêu cầu - Dù không thể khẳng định ưu thế chung, đánh giá là nếu không có AI thì một nhà nghiên cứu bảo mật khó có thể phát hiện và hoàn thiện cùng chuỗi này trong vòng 10 giờ
- Ngay cả khi được cung cấp trước lỗi Batch ban đầu, cũng khó chắc chắn có thể dựng được RCE trong khoảng thời gian đó
- GPT5.6 Sol Ultra được đánh giá đã tiến bộ lớn so với GPT5.5 trước đó ở khả năng tìm nhiều gadget mã rời rạc và nối chúng thành một chuỗi
- Khi mô hình đảm nhiệm ngày càng nhiều phần phát triển exploit kỹ thuật, con người sẽ tập trung vào việc chọn sản phẩm và bề mặt tấn công cần khảo sát, thời gian đầu tư, hướng nghiên cứu và sửa sai khi mô hình đi lệch
- Năng lực nghiên cứu meta như vậy hiện AI vẫn chưa xử lý tốt, và được dự đoán sẽ càng quan trọng khi năng lực kỹ thuật của mô hình tăng lên
1 bình luận
Ý kiến trên Hacker News
Không có căn cứ nào cho thấy 500.000 USD đã được, hoặc sẽ được, trả cho exploit kiểu này. Bài viết nói họ chỉnh sửa prompt cẩn thận như Kinh Thánh, vậy có lẽ nên bán luôn prompt đó với giá 500.000 USD thì hơn
Tác giả làm việc tại https://www.assetnote.io/, nơi cung cấp sản phẩm AI quét tự động
Các bên môi giới kiểu này thường không trả một khoản lớn một lần, mà bán quyền truy cập cho các tác nhân nhà nước rồi trả dần trong thời gian lỗi chưa được vá. Cấu trúc này nhằm ngăn việc bán lại hoặc bị khai thác cạn kiệt sớm, nên có lẽ rất ít người có thể xác nhận liệu một lỗ hổng tương tự có thực sự được nhận đủ toàn bộ số tiền hay không
Ví dụ gần nhất là mấy thiếu niên ở Florida bị bắt vì nhét mã độc vào game Steam để đánh cắp tài khoản. Dù sao thì chúng cũng sẽ bị bắt, nhưng nếu không khoe khoang trên mạng xã hội thì cuộc điều tra hẳn đã mất nhiều thời gian hơn nhiều
Nhìn vào https://github.com/WordPress/WordPress/commit/3a640e1c5e39aa... thì đến năm 2026 vẫn còn SQL injection do nối chuỗi
Họ bảo dùng
dbDeltathay vì chạy SQL trực tiếp, nhưng lại yêu cầu các quy tắc định dạng cực kỳ khó chịu như mỗi trường phải nằm trên một dòng riêng, giữaPRIMARY KEYphải có hai khoảng trắng, dùngKEYthay vìINDEX, v.v. Tên trường không được dùng dấu nháy hay backtick, kiểu dữ liệu phải viết thường, từ khóa SQL phải viết hoa, và mọi tham số độ dài cũng đều phải chỉ địnhsprintfhay khôngPayload trong các yêu cầu
POSTvàGETcó dạng/wp/v2/widgets?author_exclude=1%29+AND+1%3D0+UNION+ALL+SELECT...Principal Software Engineer @ Bluehost,WordPress Core Committer, nhưng với kiểu code này thì chữ “principal” nghe thật mỉa maiTôi chán kiểu viết gây FOMO rồi. Không phải chỉ với 25 USD là phát hiện được; ở đây còn có chuyên môn ngành để biết nên nhìn vào đâu, thăm dò thế nào, cùng dữ liệu tích lũy qua nhiều năm
Nên thôi lan truyền những câu chuyện kiểu đánh bạc và ảo tưởng rằng ai cũng đang bỏ lỡ cơ hội
Phần đáng kinh ngạc là mức giá cao của một lỗ hổng đã được biết đến, và chuyện đó cũng có thể không đúng. WordPress thường được gọi là remote root shell có kèm tính năng blog
Tôi hiểu rằng hướng dẫn người dùng phổ thông kéo-thả thì dễ hơn bảo họ commit vào repo GitHub rồi build bằng Hugo. Nhưng nhìn từ góc độ bảo mật, đó là một cấu trúc chỉ chờ một lỗ hổng xuất hiện trong core hoặc một trong hàng nghìn plugin để mở ra thực thi mã từ xa dạng dịch vụ
Bài viết thú vị, và phát hiện cũng như công bố exploit dựa trên LLM là vấn đề thực sự đáng lo. Tôi từng khiến một mô hình tạo khá nhanh mã thoát container từ một lỗ hổng leo thang đặc quyền cục bộ trên Linux
Tuy vậy, việc GPT-5.6 không chặn prompt bằng cơ chế an toàn là điều đáng ngạc nhiên. Từ GPT-5.5 trở lên có xu hướng né các tác vụ bảo mật tấn công như Opus 4.7+/Fable, nên có vẻ tác giả có thể đã được OpenAI phê duyệt an ninh mạng để nới lỏng cơ chế an toàn
Các công cụ kiểm thử bảo mật ứng dụng tĩnh (SAST) không dùng AI trước năm 2020 cũng đã bắt được rất nhiều lỗi SQL injection kiểu này, và ít nhất lẽ ra nó phải được phát hiện trong quá trình review code. Tôi tự hỏi liệu WordPress có không dùng review code hay SAST không
Một website của tôi đã bị hack bằng lỗ hổng này, nhưng may là đó là nơi không có người dùng
Kẻ tấn công đã tạo hai tài khoản quản trị trong cơ sở dữ liệu, và cài một web shell thực thi lệnh từ xa
wp-core-[12 ký tự ngẫu nhiên].phptrongwp-content/plugins/wp-core. Trongmu-plugins, chúng đặt backdoorfirewall.phptạo quản trị viên bằngGET ?sergei, thêm cả backdoorcache-seo-helper.php, và dùngfixer.phpđể sửa số phiên bản WordPress trông như đã được vá. Cuối cùng tôi quyết định từ bỏ việc dùng WordPressĐến cuối bài, tác giả bắt đầu gọi các bài viết bằng những cái tên kỳ lạ nên khó hiểu. Tôi thắc mắc vì sao lại đặt một ID là
O, ID khác là0, và dùng một ký tự đơn cùngOCPDSTtrông như ngẫu nhiên thay vìEMBED_01hayABCDEFOnghĩa làpublish/oembed_cache,Clàfuture/customize_changeset,Plàdraft/page,Dlàparse/request,Slàpublish/postcung cấp dữ liệu nhúng, cònTlàpublish/postchứa nội dung nhúng bên ngoàiPhải chăng đang giả định rằng những người có thể trả 500 nghìn đô la không có năng lực tự tận dụng GPT-5.6?
Tôi cũng dùng LLM để tìm lỗ hổng bảo mật, nhưng không thể cứ nộp nguyên kết quả rồi coi như xong; có rất nhiều người muốn làm như vậy
GPT-5.6 Sol có siêu phàm hay không không phải là câu hỏi đơn giản có/không. Máy tính đã vượt con người trong cờ vua từ vài chục năm trước, và nhìn vào bài này thì giờ đây dường như chúng cũng đã vượt con người trong việc hiểu code